From 98c230187ca1a3dee81e88a2977748d2847a8ddd Mon Sep 17 00:00:00 2001 From: Maxim Kovalov Date: Tue, 6 Aug 2019 16:46:10 +0300 Subject: [PATCH 001/207] feat(scheduler): connect scheduler to banking ui --- package.json | 1 - src/common/marketplace/inventory/index.js | 6 +- src/common/marketplace/vendors/index.js | 6 +- .../__fixtures__/ft-banking-fetched.js | 14 +- .../inventory/inventory-service.js | 13 +- .../marketplace/bank-accounts/index.jsx | 12 +- .../bank-accounts/list/offers-container.jsx | 18 +- .../bank-accounts/list/offers-table.jsx | 105 +- stories/banking-data.js | 898 +++++++++++++----- stories/banking.stories.js | 2 +- 10 files changed, 753 insertions(+), 322 deletions(-) diff --git a/package.json b/package.json index 227265c38..4a76f5fc1 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,6 @@ "check-deps": "npm-check -i common", "coveralls": "cat dist/coverage/lcov.info | coveralls", "snyk-protect": "snyk protect", - "prepare": "npm run snyk-protect", "postinstall": "rm -rf node_modules/.cache && electron-webpack dll", "build-dev-dll": "rm -rf node_modules/.cache && electron-webpack dll --env.production=false", "storybook": "start-storybook -p 6007", diff --git a/src/common/marketplace/inventory/index.js b/src/common/marketplace/inventory/index.js index f8248525f..2a8001761 100644 --- a/src/common/marketplace/inventory/index.js +++ b/src/common/marketplace/inventory/index.js @@ -57,7 +57,11 @@ export const inventorySelectors = { selectInventory: state => inventorySelectors .selectInventoryRoot(state) - .all.map(id => inventorySelectors.selectInventoryRoot(state).byId[id]) + .all.map(id => inventorySelectors.selectInventoryRoot(state).byId[id]), + selectInventoryForCategory: (state, category, status = 'active') => + inventorySelectors + .selectInventory(state) + .filter(i => i.category === category && i.status === status) }; export default reducer; diff --git a/src/common/marketplace/vendors/index.js b/src/common/marketplace/vendors/index.js index 6602b0105..69009faa2 100644 --- a/src/common/marketplace/vendors/index.js +++ b/src/common/marketplace/vendors/index.js @@ -57,7 +57,11 @@ export const vendorSelectors = { selectVendors: state => vendorSelectors .selectVendorRoot(state) - .all.map(id => vendorSelectors.selectVendorRoot(state).byId[id]) + .all.map(id => vendorSelectors.selectVendorRoot(state).byId[id]), + selectVendorsForCategory: (state, category, status = 'active') => + vendorSelectors + .selectVendors(state) + .filter(v => v.categories.includes(category) && v.status === status) }; export default reducer; diff --git a/src/main/marketplace/inventory/__fixtures__/ft-banking-fetched.js b/src/main/marketplace/inventory/__fixtures__/ft-banking-fetched.js index 706ab76c3..f3fef9a55 100644 --- a/src/main/marketplace/inventory/__fixtures__/ft-banking-fetched.js +++ b/src/main/marketplace/inventory/__fixtures__/ft-banking-fetched.js @@ -3,12 +3,12 @@ export default () => [ sku: 'FT-BNK-AD1b', vendorId: 'flagtheory_banking', priceCurrency: 'USD', - status: 'active', + status: 'inactive', name: 'Andorra AD1b', price: '1000', category: 'banking', data: { - type: ['Private'], + type: 'private', region: 'Andorra', goodFor: ['Corporate Wealth', 'Investment Funds'], testPrice: '1000', @@ -27,8 +27,14 @@ export default () => [ testTemplateId: '5d09d11c26f7be563f7e0650', activeTestPrice: true, testWalletAddress: '0x23d233933c86f93b74705cf0d236b39f474249f8', - countryName: 'Andorra', - accountTitle: 'Private Banking Account', + account: { + templateId: '5d09d11c26f7be563f7e0650', + accountCode: 'AD1b', + countryCode: 'AD', + countryName: 'Andorra', + accountTitle: 'Private Banking Account', + testTemplateId: '5d09d11c26f7be563f7e0650' + }, jurisdiction: { remote: ['Remote'], goodFor: ['Private Banking'], diff --git a/src/main/marketplace/inventory/inventory-service.js b/src/main/marketplace/inventory/inventory-service.js index 07f7aeac4..1ebed37f2 100644 --- a/src/main/marketplace/inventory/inventory-service.js +++ b/src/main/marketplace/inventory/inventory-service.js @@ -195,10 +195,10 @@ export class FlagtheoryBankingInventoryFetcher extends InventoryFetcher { const sku = `FT-BNK-${itm.accountCode || itm.countryCode}`; const name = `${itm.region} ${itm.accountCode || itm.countryCode}`; let price = itm.activeTestPrice ? itm.testPrice : itm.price; - return { + itm = { sku, name, - status: itm.templateId ? 'active' : 'inactive', + status: itm.showWallet ? 'active' : 'inactive', price, priceCurrency: 'USD', category: 'banking', @@ -206,9 +206,16 @@ export class FlagtheoryBankingInventoryFetcher extends InventoryFetcher { data: { ...itm, jurisdiction: jurisdictions[itm.countryCode] || {}, - ...(accDetails[itm.accountCode] || {}) + account: accDetails[itm.accountCode] || {} } }; + + itm.data.type = + itm.data.type && itm.data.type.length + ? itm.data.type[0].toLowerCase() + : 'private'; + + return itm; }); return items; } catch (error) { diff --git a/src/renderer/marketplace/bank-accounts/index.jsx b/src/renderer/marketplace/bank-accounts/index.jsx index 253209ec7..372f88a2e 100644 --- a/src/renderer/marketplace/bank-accounts/index.jsx +++ b/src/renderer/marketplace/bank-accounts/index.jsx @@ -1,6 +1,7 @@ import React, { Component } from 'react'; import { Route } from 'react-router-dom'; - +import { connect } from 'react-redux'; +import { marketplaceOperations } from 'common/marketplace'; import { BankAccountsTableContainer } from './list/offers-container'; import { BankAccountsDetailContainer } from './details/details-container'; import { BankAccountsCheckoutContainer } from './checkout/checkout-container'; @@ -10,6 +11,9 @@ import { BankAccountsSelectBankContainer } from './select-bank/select-bank-conta import { BankAccountsProcessStartedContainer } from './process-started/process-started-container'; class MarketplaceBankAccountsPage extends Component { + async componentDidMount() { + await this.props.dispatch(marketplaceOperations.loadMarketplaceOperation()); + } render() { const { path } = this.props.match; return ( @@ -44,5 +48,7 @@ class MarketplaceBankAccountsPage extends Component { } } -export default MarketplaceBankAccountsPage; -export { MarketplaceBankAccountsPage }; +const connected = connect()(MarketplaceBankAccountsPage); + +export default connected; +export { connected as MarketplaceBankAccountsPage }; diff --git a/src/renderer/marketplace/bank-accounts/list/offers-container.jsx b/src/renderer/marketplace/bank-accounts/list/offers-container.jsx index ca77a4531..5e7636b75 100644 --- a/src/renderer/marketplace/bank-accounts/list/offers-container.jsx +++ b/src/renderer/marketplace/bank-accounts/list/offers-container.jsx @@ -6,6 +6,7 @@ import { pricesSelectors } from 'common/prices'; import { withStyles } from '@material-ui/core/styles'; import { bankAccountsOperations, bankAccountsSelectors } from 'common/bank-accounts'; import { BankingOffersPage } from './offers-page'; +import { marketplaceSelectors } from 'common/marketplace'; import NoConnection from 'renderer/no-connection'; const styles = theme => ({}); @@ -36,22 +37,23 @@ class BankAccountsTableContainer extends Component { ) ); - activeBank = bank => bank.accountType === this.state.accountType && bank.showWallet === true; + activeBank = bank => bank.data.type === this.state.accountType; render() { - const { isLoading, bankAccounts, keyRate, isError } = this.props; + const { isLoading, keyRate, isError, vendors, inventory } = this.props; const { accountType } = this.state; if (!isLoading && isError) { return ; } - - const data = bankAccounts.filter(this.activeBank); + console.log('XXX', JSON.stringify(vendors), JSON.stringify(inventory)); + const data = inventory.filter(this.activeBank); return ( { return { - bankAccounts: bankAccountsSelectors.getMainBankAccounts(state), + vendors: marketplaceSelectors.selectVendorsForCategory(state, 'banking'), + inventory: marketplaceSelectors.selectInventoryForCategory(state, 'banking'), isLoading: bankAccountsSelectors.getLoading(state), keyRate: pricesSelectors.getRate(state, 'KEY', 'USD'), isError: bankAccountsSelectors.getError(state) diff --git a/src/renderer/marketplace/bank-accounts/list/offers-table.jsx b/src/renderer/marketplace/bank-accounts/list/offers-table.jsx index 2a36c4c42..c9fe1188c 100644 --- a/src/renderer/marketplace/bank-accounts/list/offers-table.jsx +++ b/src/renderer/marketplace/bank-accounts/list/offers-table.jsx @@ -107,8 +107,57 @@ const styles = theme => ({ } }); +const BankingOffersRow = withStyles(styles)(({ classes, bank, onDetails, keyRate }) => { + const data = bank.data; + const account = data.account; + return ( + + + + + + {data.region} + + +
+ {data.eligibility && + data.eligibility.map((tag, index) => ( + + {tag} + {index !== data.eligibility.length - 1 ? ',' : ''} + + ))} +
+
+ + {data.minDeposit} + + + + {data.goodFor && data.goodFor.map(tag => {tag})} + + + + {account.personalVisitRequired ? ( + Yes + ) : ( + No + )} + + + + + + onDetails(bank)}> + Details + + +
+ ); +}); + const BankingOffersTable = withStyles(styles)( - ({ classes, keyRate, data = [], onDetails, className }) => { + ({ classes, keyRate, inventory = [], onDetails, className }) => { return ( @@ -155,53 +204,13 @@ const BankingOffersTable = withStyles(styles)( - {data.map(bank => ( - - - - - - {bank.region} - - -
- {bank.eligibility && - bank.eligibility.map((tag, index) => ( - - {tag} - {index !== bank.eligibility.length - 1 ? ',' : ''} - - ))} -
-
- - {bank.minDeposit} - - - - {bank.goodFor && - bank.goodFor.map(tag => {tag})} - - - - {bank.personalVisitRequired ? ( - Yes - ) : ( - No - )} - - - - - - onDetails(bank)} - > - Details - - -
+ {inventory.map(bank => ( + ))}
diff --git a/stories/banking-data.js b/stories/banking-data.js index 4f1111450..f11c9a0e5 100644 --- a/stories/banking-data.js +++ b/stories/banking-data.js @@ -1,268 +1,660 @@ export const bankingOffers = [ { - id: 1, - countryCode: 'hk', - region: 'Hong Kong', - eligibility: ['Resident Individuals', 'Regional Individuals', 'International Individuals'], - eligibilityExpanded: - 'Resident Individuals, Regional Individuals, International Individuals', - minInitialDeposit: 1000, - minInitialDepositCurrency: 'USD', - goodFor: ['Transactional Banking', 'Multi-currency Cards'], - personalVisitRequired: false, - price: 500, - accountType: 'personal', - currencies: ['USD, SGD, CAD'], - cards: ['Mastercard, Visa'], - timeToOpen: '1 Month', - onlineBanking: ['Internet Home Banking'] - }, - { - id: 2, - countryCode: 'sg', - region: 'Singapore', - eligibility: ['Resident Individuals', 'Regional Individuals', 'International Individuals'], - eligibilityExpanded: - 'Resident Individuals, Regional Individuals, International Individuals', - minInitialDeposit: 500, - minInitialDepositCurrency: 'USD', - goodFor: ['Transactional Banking', 'Credit Cards'], - personalVisitRequired: true, - price: 1500, - accountType: 'personal', - currencies: ['USD, SGD, CAD'], - cards: ['Mastercard, Visa'], - timeToOpen: '1 Month', - onlineBanking: ['Internet Home Banking'] - }, - { - id: 3, - countryCode: 'ky', - region: 'Cayman', - eligibility: ['Resident Individuals', 'Regional Individuals', 'International Individuals'], - eligibilityExpanded: - 'Resident Individuals, Regional Individuals, International Individuals', - minInitialDeposit: 1000, - minInitialDepositCurrency: 'USD', - goodFor: ['Savings', 'Credit Cards', 'Multi-currency Cards'], - personalVisitRequired: false, - price: 800, - accountType: 'personal', - currencies: ['USD, SGD, CAD'], - cards: ['Mastercard, Visa'], - timeToOpen: '1 Month', - onlineBanking: ['Internet Home Banking'] - }, - { - id: 4, - countryCode: 'vg', - region: 'British Virgin Islands', - eligibility: ['Resident Individuals', 'Regional Individuals', 'International Individuals'], - eligibilityExpanded: - 'Resident Individuals, Regional Individuals, International Individuals', - minInitialDeposit: 10000, - minInitialDepositCurrency: 'USD', - goodFor: ['Transactional Banking', 'Multi-currency Cards'], - personalVisitRequired: true, - price: 3500, - accountType: 'personal', - currencies: ['USD, SGD, CAD'], - cards: ['Mastercard, Visa'], - timeToOpen: '1 Month', - onlineBanking: ['Internet Home Banking'] - }, - { - id: 5, - countryCode: 'kn', - region: 'Nevis', - eligibility: ['Resident Individuals', 'Regional Individuals', 'International Individuals'], - eligibilityExpanded: - 'Resident Individuals, Regional Individuals, International Individuals', - minInitialDeposit: 800, - minInitialDepositCurrency: 'USD', - goodFor: ['Transactional Banking', 'Multi-currency Cards'], - personalVisitRequired: false, - price: 200, - accountType: 'personal', - currencies: ['USD, SGD, CAD'], - cards: ['Mastercard, Visa'], - timeToOpen: '1 Month', - onlineBanking: ['Internet Home Banking'] - }, - - { - id: 6, - countryCode: 'hk', - region: 'Hong Kong', - eligibility: ['Resident Individuals', 'Regional Individuals', 'International Individuals'], - eligibilityExpanded: - 'Resident Individuals, Regional Individuals, International Individuals', - minInitialDeposit: 1000, - minInitialDepositCurrency: 'USD', - goodFor: ['Transactional Banking', 'Multi-currency Cards'], - personalVisitRequired: false, - price: 500, - accountType: 'business', - currencies: ['USD, SGD, CAD'], - cards: ['Mastercard, Visa'], - timeToOpen: '1 Month', - onlineBanking: ['Internet Home Banking'] - }, - { - id: 7, - countryCode: 'sg', - region: 'Singapore', - eligibility: ['Resident Individuals', 'Regional Individuals', 'International Individuals'], - minInitialDeposit: 500, - minInitialDepositCurrency: 'USD', - goodFor: ['Transactional Banking', 'Credit Cards'], - personalVisitRequired: true, - price: 1500, - accountType: 'business', - currencies: ['USD, SGD, CAD'], - cards: ['Mastercard, Visa'], - timeToOpen: '1 Month', - onlineBanking: ['Internet Home Banking'] - }, - { - id: 8, - countryCode: 'ky', - region: 'Cayman', - eligibility: ['Resident Individuals', 'Regional Individuals', 'International Individuals'], - eligibilityExpanded: - 'Resident Individuals, Regional Individuals, International Individuals', - minInitialDeposit: 1000, - minInitialDepositCurrency: 'USD', - goodFor: ['Savings', 'Credit Cards', 'Multi-currency Cards'], - personalVisitRequired: false, - price: 800, - accountType: 'business', - currencies: ['USD, SGD, CAD'], - cards: ['Mastercard, Visa'], - timeToOpen: '1 Month', - onlineBanking: ['Internet Home Banking'] - }, - { - id: 9, - countryCode: 'vg', - region: 'British Virgin Islands', - eligibility: ['Resident Individuals', 'Regional Individuals', 'International Individuals'], - eligibilityExpanded: - 'Resident Individuals, Regional Individuals, International Individuals', - minInitialDeposit: 10000, - minInitialDepositCurrency: 'USD', - goodFor: ['Transactional Banking', 'Multi-currency Cards'], - personalVisitRequired: true, - price: 3500, - accountType: 'business', - currencies: ['USD, SGD, CAD'], - cards: ['Mastercard, Visa'], - timeToOpen: '1 Month', - onlineBanking: ['Internet Home Banking'] + category: 'banking', + createdAt: 1564997439862, + data: { + account: { + accountCode: 'SG1b', + accountTitle: 'Business Priority Account', + bankCode: 'SG1bG', + bankName: 'RHB Bank', + countryCode: 'SG', + countryName: 'Singapore', + currencies: ['SGD', 'USD'], + details: + 'There are no specific restricted jurisdictions other than those that face international sanctions. A Business connection with Singapore (Supplier or Client or Management) is oftentimes required.\n\nForeign companies engaging in high-risk businesses and/or conducting an activity which is regulated in Singapore (such as Money transmitter or Forex trading) are not eligible. There are no requirements in terms of business turnover or business size.', + eligibility: 'Local and Foreign Companies (Including Offshore Companies)', + minAverageBalanceDescription: 'SGD 20,000.00\nUSD 20,000.00', + minInitialDeposit: 'USD 80,000.00', + minMonthlyBalance: 'USD 20,000.00', + onboarding: + '
    \n
  • We will assist you in filling out the KYC Questionnaires. In addition to your company and identity documents, you will need to provide certain business documentation to support your application such as invoices, letters of intent, contracts, etc.
  • \n\n
  • The Bank’s Relationship Manager will review your documentation. The banker may come back with additional questions or give green-light to your account opening process. This usually takes from 1 to 3 days.
  • \n\n
  • We will arrange your appointment with the Relationship Manager in Singapore. The appointment is usually arranged for the following week subject to the client and bankers availability.
  • \n\n
  • You will need to visit the Bank’s branch and have a 1-hour meeting with the Relationship Manager. You will need to provide original documents and sign the application forms.
  • \n\n
  • After two or three weeks, you will receive an e-mail from the Relationship Manager confirming the account opening and providing your account number. You will need to transfer the initial deposit.
  • \n\n
  • After 5-10 days, you will receive your Internet Banking credentials via courier.
  • \n\n
', + onlineBanking: ['Internet Banking', 'Mobile Banking'], + otherServices: [ + 'Trade Finance', + 'Cheque Book', + 'Fixed Deposits', + 'Wire Transfer Commissions Waived', + 'Preferential Exchange Rates' + ], + personalVisitRequired: true, + showApp: true, + showWallet: true, + templateId: '5d09d11c26f7be563f7e0650', + testTemplateId: '5d09d11c26f7be563f7e0650', + timeToOpen: '3-4 weeks' + }, + accountCode: 'SG1b', + activeTestPrice: true, + countryCode: 'SG', + eligibility: ['Offshore Companies', 'Resident Companies'], + goodFor: [ + 'Offshore Companies', + 'Transactional Banking', + 'Credit Card Processing', + 'Payment Processors', + 'Private Banking', + 'Trade Finance', + 'Credit Cards' + ], + introText: + '

Singapore is one of the largest financial centers and a top offshore banking destination due to its political and financial stability, its top-notch corporate banking facilities and its broad-range of wealth management services, investment funds, and insurance products.

\n\n

In addition, Singapore is one of the most reputed international financial centers whose banks consistently onboard companies incorporated in tax-neutral jurisdictions.

\n\n

However, banks will want to see a solid and legitimate business backing the company. Offshore companies will need to provide enough supporting business documentation such as business plans, invoices, contracts, letters of intent, etc., to satisfy the bank’s compliance requirements.

\n\n

Singapore banks are ideal for businesses that require strong transactional banking and cash management services. Companies banking in Singapore have access to some of the quickest and most affordable money transfer services worldwide.

\n\n

Import/Export companies will have access to top trade finance services such as Letter of Credit and Bank guarantees.

\n\n

Singaporean banks are considerably risk-averse and are not open for companies engaging in high-risk business activities.

\n\n

For Singaporean e-commerce businesses, a broad range of merchant accounts and credit card processing aggregators are available.

\n\n

An oasis of financial stability together with the most technologically-advanced private banking facilities, excellent customer service and a capital gains tax-free environment makes Singapore the top Asia-Pacific destination for international wealth management services.

', + jurisdiction: { + bankingDescription: + "

Singapore is the third world’s major financial center and a top offshore banking destination due to its political and financial stability, its top-notch corporate banking facilities and its broad-range of private banking services, investment funds and insurance. 

\n

In addition, Singapore is one of the most reputed international financial centers whose banks consistently onboard companies incorporated in tax-neutral jurisdictions.

\n

However, banks will want to see a solid and legit business backing the company. Offshore companies will need to provide enough supporting business documentation such as business plans, invoices, contracts, letters of intent, etc. to satisfy the bank's compliance requirements.

\n

Singapore banks are ideal for businesses that require strong transactional banking and cash management services. Companies banking in Singapore have access to some of the quickest and most affordable money transfer services.

\n

Import/Export companies will have access to top trade finance services such as Letter of Credit and Bank guarantees.

\n

Singaporean banks are considerably risk-averse and are not open for companies engaging in high-risk business activities.

\n

For Singaporean e-commerce businesses, a broad range of merchant accounts and credit card processing aggregators are available.

\n

An oasis of financial stability together with the most technology advanced private banking facilities, an excellent customer service and a capital gains tax-free environment makes Singapore the top Asia-Pacific destination for international wealth management services. 

", + businessAccounts: [ + 'Offshore Company', + 'Regional Company', + 'Resident Company', + 'Nonresident Onshore Company' + ], + countryCode: 'SG', + countryDetails: + '

The Republic of Singapore, also known as Lion City or the Little Red Dot, is an island city-state of Asia, made up of a main island and other sixty-two islets, and founding member of the ASEAN.

\n

It is located to the south of the State of Johor in the peninsula of Malaysia and to the north of the islands Riau of Indonesia, separated of these by Strait of Singapore. Its population is about 5.5 million, of which about 75 percent are Chinese, and the rest are Malay, Indian or Eurasian minorities. This multiculturalism diversity is reflected in the four official languages of the country, English, Chinese, Malay and Tamil. Its official currency is the Singapore Dollar (SGD), which is also accepted as customary tender in Brunei. Alike, the Brunei Dollar (BND) is customarily accepted in Singapore.

\n

Singapore is a unitary multiparty parliamentary republic, with a Westminster system of unicameral parliamentary government.

\n

Singapore is one of the main global cities and one of the hubs of world trade, third-largest oil refining and trading centre, third largest financial center and one of the largest freight port worldwide. Singapore is the third country with the highest per capita income worldwide, in terms of purchasing power parity, as well as being among the first countries on the international lists of education, with one of the highest skilled workforce worldwide, health, political transparency and economic competitiveness.

\n

Its globalized and diversified economy depends especially on international trade, refining imported raw goods to reexport, and an export-oriented manufacturing sector, mainly chemistry, oil refining, being one of the top three export refining centers in the world, mechanical engineering, biotechnology and biomedical sciences. Singapore has one of the seaports that handles the largest annual cargo volume worldwide, both in tonnage and in the number of containers.

\n

The country is also an important international financial hub, leading world’s private banking sector, offering top-notch corporate banking facilities and a broad-range of banking services, investment funds and insurance services, among others. It also has the fourth largest currency exchange and capital market worldwide, behind New York, London and Tokyo.

\n

All supported by an investor and entrepreneurship friendly tax policy. With a territorial tax system, a low tax burden and the availability of several tax breaks and incentives for startups and technological innovation.

\n

Singapore welcomes thousands of foreign investors, expats entrepreneurs and multinational companies’ employees. Singapore’s immigration policy is geared towards attracting foreign talent, with several visa schemes to attract high-skilled foreign employees, entrepreneurs and investors.

', + countryName: 'Singapore', + goodFor: [ + 'Offshore Companies', + 'Transactional Banking', + 'Credit Card Processing', + 'Payment Processors', + 'Private Banking', + 'Trade Finance', + 'Credit Cards' + ], + minDeposit: ['Medium'], + payments: [ + 'PayPal', + 'Amazon Payouts', + 'Merchant Accounts', + 'Stripe', + 'Onshore CC Aggregator', + 'Prepaid / Credit Cards' + ], + personalAccounts: ['Regional'], + remote: ['In-Person'], + showApp: true, + wealthManagement: ['International'] + }, + minDeposit: 'USD 1,000.00', + personalVisitRequired: false, + price: '1750', + priceOptions: '- Corporate Bank Account (1750)', + region: 'Singapore', + shop: 'https://flagtheory.com/product/singaporean-bank-account/', + showApp: true, + showWallet: true, + templateId: '5d09d11c26f7be563f7e0650', + testDidAddress: '0xee10a3335f48e10b444e299cf017d57879109c1e32cec3e31103ceca7718d0ec', + testPrice: '0.25', + testTemplateId: '5d09d11c26f7be563f7e0650', + testWalletAddress: '0x23d233933c86f93b74705cf0d236b39f474249f8', + type: 'business', + walletAddress: '0x6ce3bdd91d3b9f55ec206970e75701043fba751d', + walletDescription: + '

Our banking support service is not just a mere introduction to the bank. We assist you in filling out the business questionnaires appropriately and help you understand and provide business details, commercial information and purpose/use of the bank account that a given bank wants to know in order to approve your account application. Banks want certainty and clarity on how the account will be used. Everything must be watertight. We will work with you to make sure there is minimal ‘back and forth’ and a smooth account opening process.

\n\n

Our banking support services include introductions to payment processors and merchant accounts to better support our e-commerce clients. Whether you just need standard credit card processing or specialized services for high-risk processing, we are happy to help you with introductions that can empower your business.

\n\n

\nBank Account opening requirements are subject to change at the discretion of the bank. There might be additional fees charged by the bank itself. Bank account opening is not guaranteed and is subject to the bank policies and compliance department. There might be restrictions on UBO nationalities, business activities and/or jurisdictions. A refund is guaranteed if the account is not successfully opened, but a 15% administrative fee applies.

' + }, + description: '', + env: 'development', + id: 318, + name: 'Singapore SG1b', + parentSku: null, + price: '0.25', + priceCurrency: 'USD', + sku: 'FT-BNK-SG1b', + status: 'active', + updatedAt: 1565097777686, + vendorId: 'flagtheory_banking' }, { - id: 10, - countryCode: 'kn', - region: 'Nevis', - eligibility: ['Resident Individuals', 'Regional Individuals', 'International Individuals'], - eligibilityExpanded: - 'Resident Individuals, Regional Individuals, International Individuals', - minInitialDeposit: 800, - minInitialDepositCurrency: 'USD', - goodFor: ['Transactional Banking', 'Multi-currency Cards'], - personalVisitRequired: false, - price: 200, - accountType: 'business', - currencies: ['USD, SGD, CAD'], - cards: ['Mastercard, Visa'], - timeToOpen: '1 Month', - onlineBanking: ['Internet Home Banking'] - }, - - { - id: 11, - countryCode: 'hk', - region: 'Hong Kong', - eligibility: ['Resident Individuals', 'Regional Individuals', 'International Individuals'], - eligibilityExpanded: - 'Resident Individuals, Regional Individuals, International Individuals', - minInitialDeposit: 1000, - minInitialDepositCurrency: 'USD', - goodFor: ['Transactional Banking', 'Multi-currency Cards'], - personalVisitRequired: false, - price: 500, - accountType: 'private', - currencies: ['USD, SGD, CAD'], - cards: ['Mastercard, Visa'], - timeToOpen: '1 Month', - onlineBanking: ['Internet Home Banking'] + category: 'banking', + createdAt: 1564997439862, + data: { + account: { + accountCode: 'SG2b', + accountTitle: 'Personal Account', + bankCode: 'SG2bA', + bankName: 'UOB Bank', + cards: ['Visa Debit (SGD)', 'Mastercard Debit', 'Credit Cards'], + countryCode: 'SG', + countryName: 'Singapore', + currencies: [ + 'Multi-currency', + 'SGD', + 'USD', + 'EUR', + 'AUD', + 'JPY', + 'HKD', + 'CHF', + 'GBP' + ], + eligibility: + 'Individuals with a regional connection (e.g. Southeast Asian business, employment, residency…etc)\nIndividuals willing to invest in bank’s financial and insurance products (e.g. life insurance policy, investment funds…etc.)', + minAverageBalanceDescription: 'SGD 1,000.00', + minInitialDeposit: 'SGD 1,000.00', + minMonthlyBalance: 'SGD 1,000.00', + onboarding: + '
    \n
  • We will assist you in filling out the KYC Questionnaires.
  • \n\n
  • The Bank’s Relationship Manager will review your documentation. The banker may come back with additional questions or give green-light to your account opening process. This usually takes from 1 to 3 days.
  • \n\n
  • We will arrange your appointment with the Relationship Manager in Singapore. The appointment is usually arranged for the following week subject to the client and banker availability.
  • \n\n
  • You will need to visit the Bank’s branch and have a 1-hour meeting with the Relationship Manager. You will need to provide original documents and sign the application forms.
  • \n\n
  • Personal Accounts are opened on the spot, internet banking credentials will be set the same day and you will receive the debit card the same day. You may elect to pick up your SecureToken device after 5 business days or receive it in the mailing address provided.
  • \n\n
', + onlineBanking: ['Internet Banking', 'Mobile Banking', 'Currency Exchange App'], + otherServices: ['Term-deposits', 'Interest-bearing accounts'], + personalVisitRequired: true, + showApp: true, + showWallet: true, + templateId: '5d09d11c26f7be563f7e0650', + testTemplateId: '5d09d11c26f7be563f7e0650', + timeToOpen: '1 week' + }, + accountCode: 'SG2b', + activeTestPrice: true, + countryCode: 'SG', + eligibility: ['International Individuals'], + goodFor: ['Offshore Savings'], + introText: + '

Singapore is one of the largest financial centers and a top offshore banking destination due to its political and financial stability, its top-notch corporate banking facilities and its broad-range of wealth management services, investment funds, and insurance products.

\n\n

In addition, Singapore is one of the most reputed international financial centers whose banks consistently onboard companies incorporated in tax-neutral jurisdictions.

\n\n

However, banks will want to see a solid and legitimate business backing the company. Offshore companies will need to provide enough supporting business documentation such as business plans, invoices, contracts, letters of intent, etc., to satisfy the bank’s compliance requirements.

\n\n

Singapore banks are ideal for businesses that require strong transactional banking and cash management services. Companies banking in Singapore have access to some of the quickest and most affordable money transfer services worldwide.

\n\n

Import/Export companies will have access to top trade finance services such as Letter of Credit and Bank guarantees.

\n\n

Singaporean banks are considerably risk-averse and are not open for companies engaging in high-risk business activities.

\n\n

For Singaporean e-commerce businesses, a broad range of merchant accounts and credit card processing aggregators are available.

\n\n

An oasis of financial stability together with the most technologically advanced private banking facilities, excellent customer service and a capital gains tax-free environment makes Singapore the top Asia-Pacific destination for international wealth management services.

', + jurisdiction: { + bankingDescription: + "

Singapore is the third world’s major financial center and a top offshore banking destination due to its political and financial stability, its top-notch corporate banking facilities and its broad-range of private banking services, investment funds and insurance. 

\n

In addition, Singapore is one of the most reputed international financial centers whose banks consistently onboard companies incorporated in tax-neutral jurisdictions.

\n

However, banks will want to see a solid and legit business backing the company. Offshore companies will need to provide enough supporting business documentation such as business plans, invoices, contracts, letters of intent, etc. to satisfy the bank's compliance requirements.

\n

Singapore banks are ideal for businesses that require strong transactional banking and cash management services. Companies banking in Singapore have access to some of the quickest and most affordable money transfer services.

\n

Import/Export companies will have access to top trade finance services such as Letter of Credit and Bank guarantees.

\n

Singaporean banks are considerably risk-averse and are not open for companies engaging in high-risk business activities.

\n

For Singaporean e-commerce businesses, a broad range of merchant accounts and credit card processing aggregators are available.

\n

An oasis of financial stability together with the most technology advanced private banking facilities, an excellent customer service and a capital gains tax-free environment makes Singapore the top Asia-Pacific destination for international wealth management services. 

", + businessAccounts: [ + 'Offshore Company', + 'Regional Company', + 'Resident Company', + 'Nonresident Onshore Company' + ], + countryCode: 'SG', + countryDetails: + '

The Republic of Singapore, also known as Lion City or the Little Red Dot, is an island city-state of Asia, made up of a main island and other sixty-two islets, and founding member of the ASEAN.

\n

It is located to the south of the State of Johor in the peninsula of Malaysia and to the north of the islands Riau of Indonesia, separated of these by Strait of Singapore. Its population is about 5.5 million, of which about 75 percent are Chinese, and the rest are Malay, Indian or Eurasian minorities. This multiculturalism diversity is reflected in the four official languages of the country, English, Chinese, Malay and Tamil. Its official currency is the Singapore Dollar (SGD), which is also accepted as customary tender in Brunei. Alike, the Brunei Dollar (BND) is customarily accepted in Singapore.

\n

Singapore is a unitary multiparty parliamentary republic, with a Westminster system of unicameral parliamentary government.

\n

Singapore is one of the main global cities and one of the hubs of world trade, third-largest oil refining and trading centre, third largest financial center and one of the largest freight port worldwide. Singapore is the third country with the highest per capita income worldwide, in terms of purchasing power parity, as well as being among the first countries on the international lists of education, with one of the highest skilled workforce worldwide, health, political transparency and economic competitiveness.

\n

Its globalized and diversified economy depends especially on international trade, refining imported raw goods to reexport, and an export-oriented manufacturing sector, mainly chemistry, oil refining, being one of the top three export refining centers in the world, mechanical engineering, biotechnology and biomedical sciences. Singapore has one of the seaports that handles the largest annual cargo volume worldwide, both in tonnage and in the number of containers.

\n

The country is also an important international financial hub, leading world’s private banking sector, offering top-notch corporate banking facilities and a broad-range of banking services, investment funds and insurance services, among others. It also has the fourth largest currency exchange and capital market worldwide, behind New York, London and Tokyo.

\n

All supported by an investor and entrepreneurship friendly tax policy. With a territorial tax system, a low tax burden and the availability of several tax breaks and incentives for startups and technological innovation.

\n

Singapore welcomes thousands of foreign investors, expats entrepreneurs and multinational companies’ employees. Singapore’s immigration policy is geared towards attracting foreign talent, with several visa schemes to attract high-skilled foreign employees, entrepreneurs and investors.

', + countryName: 'Singapore', + goodFor: [ + 'Offshore Companies', + 'Transactional Banking', + 'Credit Card Processing', + 'Payment Processors', + 'Private Banking', + 'Trade Finance', + 'Credit Cards' + ], + minDeposit: ['Medium'], + payments: [ + 'PayPal', + 'Amazon Payouts', + 'Merchant Accounts', + 'Stripe', + 'Onshore CC Aggregator', + 'Prepaid / Credit Cards' + ], + personalAccounts: ['Regional'], + remote: ['In-Person'], + showApp: true, + wealthManagement: ['International'] + }, + minDeposit: 'SGD 1,000', + price: '850', + priceOptions: '- Personal Bank Account (850)', + region: 'Singapore', + shop: 'https://flagtheory.com/product/singaporean-bank-account/', + showApp: true, + showWallet: true, + templateId: '5d09d11c26f7be563f7e0650', + testDidAddress: '0xee10a3335f48e10b444e299cf017d57879109c1e32cec3e31103ceca7718d0ec', + testPrice: '0.25', + testTemplateId: '5d09d11c26f7be563f7e0650', + testWalletAddress: '0x23d233933c86f93b74705cf0d236b39f474249f8', + type: 'personal', + walletAddress: '0x6ce3bdd91d3b9f55ec206970e75701043fba751d', + walletDescription: + '

Our banking support service is not just a mere introduction to the bank. We assist you in filling out the business questionnaires appropriately and help you understand and provide business details, commercial information and purpose/use of the bank account that a given bank wants to know in order to approve your account application. Banks want certainty and clarity on how the account will be used. Everything must be watertight. We will work with you to make sure there is minimal ‘back and forth’ and a smooth account opening process.

\n\n

Our banking support services include introductions to payment processors and merchant accounts to better support our e-commerce clients. Whether you just need standard credit card processing or specialized services for high-risk processing, we are happy to help you with introductions that can empower your business.

\n\n

\nBank Account opening requirements are subject to change at the discretion of the bank. There might be additional fees charged by the bank itself. Bank account opening is not guaranteed and is subject to the bank policies and compliance department. There might be restrictions on UBO nationalities, business activities and/or jurisdictions. A refund is guaranteed if the account is not successfully opened, but a 15% administrative fee applies.

' + }, + description: '', + env: 'development', + id: 319, + name: 'Singapore SG2b', + parentSku: null, + price: '0.25', + priceCurrency: 'USD', + sku: 'FT-BNK-SG2b', + status: 'active', + updatedAt: 1565097777686, + vendorId: 'flagtheory_banking' }, { - id: 12, - countryCode: 'sg', - region: 'Singapore', - eligibility: ['Resident Individuals', 'Regional Individuals', 'International Individuals'], - eligibilityExpanded: - 'Resident Individuals, Regional Individuals, International Individuals', - minInitialDeposit: 500, - minInitialDepositCurrency: 'USD', - goodFor: ['Transactional Banking', 'Credit Cards'], - personalVisitRequired: true, - price: 1500, - accountType: 'private', - currencies: ['USD, SGD, CAD'], - cards: ['Mastercard, Visa'], - timeToOpen: '1 Month', - onlineBanking: ['Internet Home Banking'] + category: 'banking', + createdAt: 1564997439862, + data: { + account: { + accountCode: 'SG3b', + accountTitle: 'Wealth Management Account', + bankCode: 'SG3bC', + bankName: 'Citibank Singapore', + cards: ['Debit Card (SGD)', 'Credit Card (USD)'], + countryCode: 'SG', + countryName: 'Singapore', + currencies: ['Multi-currency'], + eligibility: 'International Individuals', + minAverageBalanceDescription: 'USD 200,000.00', + minInitialDeposit: 'USD 200,000.00', + minMonthlyBalance: 'N/A', + onboarding: + '
    \n
  • We will assist you in filling out the KYC Questionnaires. You will need to provide certified copies of your identity documents and proof of address.
  • \n\n
  • The Bank’s Relationship Manager will review your documentation. The banker may come back with additional questions or give green-light to your account opening process. This usually takes from 1 to 3 days.
  • \n\n
  • Once the relationship manager has confirmed that your documents meet the bank’s requirements. You will be required to mail them to Singapore.
  • \n\n
  • Once the bank receives the original certified copies of your documents, the relationship manager will proceed to open your account.
  • \n\n
  • Once your account is opened you will receive your Bank Account details via SMS and a welcome e-mail from the bank. Debit Card and Internet Banking credentials will be sent via courier.
  • \n
', + onlineBanking: ['Internet Banking', 'Mobile Banking'], + otherServices: [ + 'Savings Account', + 'Term-deposits', + 'FOREX', + 'Brokerage Accounts', + 'Investment Services', + 'Dedicated Wealth Planner' + ], + showApp: true, + showWallet: true, + templateId: '5d09d11c26f7be563f7e0650', + testTemplateId: '5d09d11c26f7be563f7e0650', + timeToOpen: '2 weeks' + }, + accountCode: 'SG3b', + activeTestPrice: true, + countryCode: 'SG', + eligibility: ['International Individuals'], + goodFor: ['Private Banking', 'Investment Funds', 'Credit Cards'], + introText: + '

Singapore is one of the largest financial centers and a top offshore banking destination due to its political and financial stability, its top-notch corporate banking facilities and its broad-range of wealth management services, investment funds, and insurance products.

\n\n

In addition, Singapore is one of the most reputed international financial centers whose banks consistently onboard companies incorporated in tax-neutral jurisdictions.

\n\n

However, banks will want to see a solid and legitimate business backing the company. Offshore companies will need to provide enough supporting business documentation such as business plans, invoices, contracts, letters of intent, etc., to satisfy the bank’s compliance requirements.

\n\n

Singapore banks are ideal for businesses that require strong transactional banking and cash management services. Companies banking in Singapore have access to some of the quickest and most affordable money transfer services worldwide.

\n\n

Import/Export companies will have access to top trade finance services such as Letter of Credit and Bank guarantees.

\n\n

Singaporean banks are considerably risk-averse and are not open for companies engaging in high-risk business activities.

\n\n

For Singaporean e-commerce businesses, a broad range of merchant accounts and credit card processing aggregators are available.

\n\n

An oasis of financial stability together with the most technologically advanced private banking facilities, excellent customer service and a capital gains tax-free environment makes Singapore the top Asia-Pacific destination for international wealth management services.

', + jurisdiction: { + bankingDescription: + "

Singapore is the third world’s major financial center and a top offshore banking destination due to its political and financial stability, its top-notch corporate banking facilities and its broad-range of private banking services, investment funds and insurance. 

\n

In addition, Singapore is one of the most reputed international financial centers whose banks consistently onboard companies incorporated in tax-neutral jurisdictions.

\n

However, banks will want to see a solid and legit business backing the company. Offshore companies will need to provide enough supporting business documentation such as business plans, invoices, contracts, letters of intent, etc. to satisfy the bank's compliance requirements.

\n

Singapore banks are ideal for businesses that require strong transactional banking and cash management services. Companies banking in Singapore have access to some of the quickest and most affordable money transfer services.

\n

Import/Export companies will have access to top trade finance services such as Letter of Credit and Bank guarantees.

\n

Singaporean banks are considerably risk-averse and are not open for companies engaging in high-risk business activities.

\n

For Singaporean e-commerce businesses, a broad range of merchant accounts and credit card processing aggregators are available.

\n

An oasis of financial stability together with the most technology advanced private banking facilities, an excellent customer service and a capital gains tax-free environment makes Singapore the top Asia-Pacific destination for international wealth management services. 

", + businessAccounts: [ + 'Offshore Company', + 'Regional Company', + 'Resident Company', + 'Nonresident Onshore Company' + ], + countryCode: 'SG', + countryDetails: + '

The Republic of Singapore, also known as Lion City or the Little Red Dot, is an island city-state of Asia, made up of a main island and other sixty-two islets, and founding member of the ASEAN.

\n

It is located to the south of the State of Johor in the peninsula of Malaysia and to the north of the islands Riau of Indonesia, separated of these by Strait of Singapore. Its population is about 5.5 million, of which about 75 percent are Chinese, and the rest are Malay, Indian or Eurasian minorities. This multiculturalism diversity is reflected in the four official languages of the country, English, Chinese, Malay and Tamil. Its official currency is the Singapore Dollar (SGD), which is also accepted as customary tender in Brunei. Alike, the Brunei Dollar (BND) is customarily accepted in Singapore.

\n

Singapore is a unitary multiparty parliamentary republic, with a Westminster system of unicameral parliamentary government.

\n

Singapore is one of the main global cities and one of the hubs of world trade, third-largest oil refining and trading centre, third largest financial center and one of the largest freight port worldwide. Singapore is the third country with the highest per capita income worldwide, in terms of purchasing power parity, as well as being among the first countries on the international lists of education, with one of the highest skilled workforce worldwide, health, political transparency and economic competitiveness.

\n

Its globalized and diversified economy depends especially on international trade, refining imported raw goods to reexport, and an export-oriented manufacturing sector, mainly chemistry, oil refining, being one of the top three export refining centers in the world, mechanical engineering, biotechnology and biomedical sciences. Singapore has one of the seaports that handles the largest annual cargo volume worldwide, both in tonnage and in the number of containers.

\n

The country is also an important international financial hub, leading world’s private banking sector, offering top-notch corporate banking facilities and a broad-range of banking services, investment funds and insurance services, among others. It also has the fourth largest currency exchange and capital market worldwide, behind New York, London and Tokyo.

\n

All supported by an investor and entrepreneurship friendly tax policy. With a territorial tax system, a low tax burden and the availability of several tax breaks and incentives for startups and technological innovation.

\n

Singapore welcomes thousands of foreign investors, expats entrepreneurs and multinational companies’ employees. Singapore’s immigration policy is geared towards attracting foreign talent, with several visa schemes to attract high-skilled foreign employees, entrepreneurs and investors.

', + countryName: 'Singapore', + goodFor: [ + 'Offshore Companies', + 'Transactional Banking', + 'Credit Card Processing', + 'Payment Processors', + 'Private Banking', + 'Trade Finance', + 'Credit Cards' + ], + minDeposit: ['Medium'], + payments: [ + 'PayPal', + 'Amazon Payouts', + 'Merchant Accounts', + 'Stripe', + 'Onshore CC Aggregator', + 'Prepaid / Credit Cards' + ], + personalAccounts: ['Regional'], + remote: ['In-Person'], + showApp: true, + wealthManagement: ['International'] + }, + minDeposit: 'SGD 200,000', + personalVisitRequired: true, + price: '850', + priceOptions: '- Wealth Management Bank Account (850\n)', + region: 'Singapore', + shop: 'https://flagtheory.com/product/singaporean-bank-account/', + showApp: true, + showWallet: true, + templateId: '5d09d11c26f7be563f7e0650', + testDidAddress: '0xee10a3335f48e10b444e299cf017d57879109c1e32cec3e31103ceca7718d0ec', + testPrice: '0.25', + testTemplateId: '5d09d11c26f7be563f7e0650', + testWalletAddress: '0x23d233933c86f93b74705cf0d236b39f474249f8', + type: 'private', + walletAddress: '0x6ce3bdd91d3b9f55ec206970e75701043fba751d', + walletDescription: + '

Our banking support service is not just a mere introduction to the bank. We assist you in filling out the business questionnaires appropriately and help you understand and provide business details, commercial information and purpose/use of the bank account that a given bank wants to know in order to approve your account application. Banks want certainty and clarity on how the account will be used. Everything must be watertight. We will work with you to make sure there is minimal ‘back and forth’ and a smooth account opening process.

\n\n

Our banking support services include introductions to payment processors and merchant accounts to better support our e-commerce clients. Whether you just need standard credit card processing or specialized services for high-risk processing, we are happy to help you with introductions that can empower your business.

\n\n

\nBank Account opening requirements are subject to change at the discretion of the bank. There might be additional fees charged by the bank itself. Bank account opening is not guaranteed and is subject to the bank policies and compliance department. There might be restrictions on UBO nationalities, business activities and/or jurisdictions. A refund is guaranteed if the account is not successfully opened, but a 15% administrative fee applies.

' + }, + description: '', + env: 'development', + id: 320, + name: 'Singapore SG3b', + parentSku: null, + price: '0.25', + priceCurrency: 'USD', + sku: 'FT-BNK-SG3b', + status: 'active', + updatedAt: 1565097777686, + vendorId: 'flagtheory_banking' }, { - id: 13, - countryCode: 'ky', - region: 'Cayman', - eligibility: ['Resident Individuals', 'Regional Individuals', 'International Individuals'], - minInitialDeposit: 1000, - minInitialDepositCurrency: 'USD', - goodFor: ['Savings', 'Credit Cards', 'Multi-currency Cards'], - personalVisitRequired: false, - price: 800, - accountType: 'private', - onlineBanking: ['Internet Home Banking'] + category: 'banking', + createdAt: 1564997439862, + data: { + account: { + accountCode: 'HK2b', + accountTitle: 'Personal Savings Account', + bankCode: 'HK2bA', + bankName: 'Bank Of China (Hong Kong)', + cards: ['UnionPay Debit (HKD)', 'UnionPay Debit (CNY)'], + countryCode: 'HK', + countryName: 'Hong Kong', + currencies: ['HKD', 'USD', 'Multi-currency'], + eligibility: 'International Individuals (A connection with HK is a must)', + minAverageBalanceDescription: 'HKD 10,000.00', + minInitialDeposit: 'HKD 10,000.00', + minMonthlyBalance: 'HKD 10,000.00', + onboarding: + '
    \n
  • We will assist you in filling out the KYC Questionnaires.
  • \n
  • The Bank’s Relationship Manager will review your documentation. The banker may come back with additional questions or give green-light to your account opening process. This usually takes 1 week.
  • \n
  • We will arrange your appointment with the Relationship Manager in Hong Kong. The appointment is usually the following week.
  • \n
  • You will need to visit the Bank’s branch to provide original documents, have an interview with the banker and sign application forms.
  • \n
  • The bank account will be opened on the spot. You will receive your account details, internet banking credentials, secure Token device and your debit card the same day.
  • \n
', + onlineBanking: ['Internet Banking', 'Mobile Banking'], + otherServices: ['Term-deposits', 'Investment Services', 'Insurance Products'], + personalVisitRequired: true, + showApp: true, + showWallet: true, + templateId: '5d09d11c26f7be563f7e0650', + testTemplateId: '5d09d11c26f7be563f7e0650', + timeToOpen: '2-3 weeks' + }, + accountCode: 'HK2b', + activeTestPrice: true, + countryCode: 'HK', + eligibility: ['International Individuals'], + goodFor: ['Offshore Savings'], + introText: + '

Hong Kong is the largest financial hub in Asia and one of the safest and more convenient places to bank. Hong Kong banks are some of the most solvent and liquid banks worldwide.

\n

There are no exchange controls and accounts are available in multiple currencies, in addition to a large variety of investment and insurance products.

\n

Hong Kong banks are ideal for both individuals and businesses that require strong cash management services in various currencies and that have strong investment needs.

\n

Hong Kong is also the gateway to one of the largest and fastest-growing markets worldwide: China. Hong Kong banks offer RMB accounts and payment cards.

\n

Import/Export companies will have access to top trade finance services such as Letter of Credit and Bank guarantees.

\n

Hong Kong online businesses with HK bank accounts also have access to a broad range of merchant accounts and credit card processing aggregators.

\n

Hong Kong banks are also available for companies incorporated in tax-neutral jurisdictions. However, banks will want to see a solid business background, and a relatively low-risk commercial activity to onboard an offshore company.

\n

Offshore companies will need to provide enough supporting business documentation such as business plans, invoices, contracts, letters of intent, etc., to satisfy the bank’s compliance requirements.

\n

All in all, Hong Kong is a perfect banking location for local and international businesses, companies doing business in China and individuals looking for strong wealth management and investment services.

', + jurisdiction: { + businessAccounts: [ + 'Offshore Company', + 'Nonresident Onshore Company', + 'Resident Company', + 'Regional Company' + ], + countryCode: 'HK', + countryDetails: + '

Hong Kong is a Special Administrative Region of the People’s Republic of China (Hong Kong SAR). Its official languages are English and Cantonese.

\n

Although it is part of the People’s Republic of China, the region maintains an independent economic, administrative and judicial system, and even its own currency, system of customs and external borders.  Its official legal tender currency is the Hong Kong Dollar (HKD), pegged to the USD, which is the ninth most traded currency worldwide.

\n

The legislative council is the Hong Kong Parliament, which is formed by 60-members, half elected by universal suffrage in geographical circumscriptions, while the other 30 are elected by groups of representatives from different economic and social sectors.

\n

Its public finances are characterized by its sustainability, with no public net debt, continuous government surplus and ample foreign exchange reserves, all supported by rigorous anti-corruption measures.

\n

Hong Kong’s economy is mainly based on financial services, tourism, wholesale and retail trade, and international trade, especially trade between China and the rest of the world. Hong Kong is one of the world’s major financial hub, ranking eleventh worldwide in volume of banking operations and the Hong Kong Stock Exchange being the second largest capital market in Asia, after the Tokyo Stock Exchange.

', + countryName: 'Hong Kong', + goodFor: [ + 'Transactional Banking', + 'Credit Card Processing', + 'Payment Processors', + 'Private Banking', + 'Trade Finance' + ], + minDeposit: ['Low'], + payments: [ + 'PayPal', + 'Amazon Payouts', + 'Merchant Accounts', + 'Stripe', + 'Onshore CC Aggregator', + 'Prepaid / Credit Cards' + ], + personalAccounts: ['International'], + remote: ['In-Person'], + showApp: true, + wealthManagement: ['International'] + }, + minDeposit: 'HKD 10,000.00', + personalVisitRequired: true, + price: '1150', + priceOptions: '- Personal Bank Account (1150)', + region: 'Hong Kong', + shop: 'https://flagtheory.com/product/open-a-bank-account-in-hong-kong/', + showApp: true, + showWallet: true, + templateId: '5d09d11c26f7be563f7e0650', + testDidAddress: '0xee10a3335f48e10b444e299cf017d57879109c1e32cec3e31103ceca7718d0ec', + testPrice: '0.25', + testTemplateId: '5d09d11c26f7be563f7e0650', + testWalletAddress: '0x23d233933c86f93b74705cf0d236b39f474249f8', + type: 'personal', + walletAddress: '0x6ce3bdd91d3b9f55ec206970e75701043fba751d', + walletDescription: + '

Our banking support service is not just a mere introduction to the bank. We assist you in filling out the business questionnaires appropriately and help you understand and provide business details, commercial information and purpose/use of the bank account that a given bank wants to know in order to approve your account application. Banks want certainty and clarity on how the account will be used. Everything must be watertight. We will work with you to make sure there is minimal ‘back and forth’ and a smooth account opening process.

\n\n

Our banking support services include introductions to payment processors and merchant accounts to better support our e-commerce clients. Whether you just need standard credit card processing or specialized services for high-risk processing, we are happy to help you with introductions that can empower your business.

\n\n

\nBank Account opening requirements are subject to change at the discretion of the bank. There might be additional fees charged by the bank itself. Bank account opening is not guaranteed and is subject to the bank policies and compliance department. There might be restrictions on UBO nationalities, business activities and/or jurisdictions. A refund is guaranteed if the account is not successfully opened, but a 15% administrative fee applies.

' + }, + description: '', + env: 'development', + id: 321, + name: 'Hong Kong HK2b', + parentSku: null, + price: '0.25', + priceCurrency: 'USD', + sku: 'FT-BNK-HK2b', + status: 'active', + updatedAt: 1565097777686, + vendorId: 'flagtheory_banking' }, { - id: 14, - countryCode: 'vg', - region: 'British Virgin Islands', - eligibility: ['Resident Individuals', 'Regional Individuals', 'International Individuals'], - eligibilityExpanded: - 'Resident Individuals, Regional Individuals, International Individuals', - minInitialDeposit: 10000, - minInitialDepositCurrency: 'USD', - goodFor: ['Transactional Banking', 'Multi-currency Cards'], - personalVisitRequired: true, - price: 3500, - accountType: 'private', - currencies: ['USD, SGD, CAD'], - cards: ['Mastercard, Visa'], - timeToOpen: '1 Month', - onlineBanking: ['Internet Home Banking'] + category: 'banking', + createdAt: 1564997439862, + data: { + account: { + accountCode: 'HK3b', + accountTitle: 'Wealth Management Account', + bankCode: 'HK3bA', + bankName: 'DBS Bank', + cards: [ + 'UnionPay Debit (HKD)', + 'UnionPay Debit (CNY)', + 'Mastercard Credit Card (USD)', + 'Mastercard Credit Card (HKD)', + 'Visa Credit (USD)', + 'Visa Credit (HKD)' + ], + countryCode: 'HK', + countryName: 'Hong Kong', + currencies: ['HKD', 'USD', 'Multi-currency'], + eligibility: 'International Individuals and Companies', + minInitialDeposit: 'HKD 1,000,000.00', + minMonthlyBalance: 'N/A', + onboarding: + '
    \n
  • We will assist you in filling out the KYC Questionnaires.
  • \n
  • The Bank’s Relationship Manager will review your documentation. The banker may come back with additional questions or give green-light to your account opening process. This usually takes 1 week.
  • \n
  • We will arrange your appointment with the Relationship Manager in Hong Kong. The appointment is usually arranged for the following week subject to the client and bankers availability.
  • \n
  • You will need to visit the Bank’s branch and have a 1-hour meeting with the Relationship Manager. You will need to provide original documents and sign the application forms.
  • \n
  • Wealth Management Accounts are opened on the spot, you will receive your cards, and your internet banking credentials will be set the same day.
  • \n
', + onlineBanking: ['Internet Banking', 'Mobile Banking'], + otherServices: [ + 'iWealth', + 'Trading Platform', + 'FOREX', + 'Investment Services', + 'Term-deposits', + 'Dedicated Wealth Planner' + ], + personalVisitRequired: true, + showApp: true, + showWallet: true, + templateId: '5d09d11c26f7be563f7e0650', + testTemplateId: '5d09d11c26f7be563f7e0650', + timeToOpen: '2-3 weeks' + }, + accountCode: 'HK3b', + activeTestPrice: true, + countryCode: 'HK', + eligibility: ['International Individuals'], + goodFor: ['Private Banking', 'Investment Funds', 'Credit Cards'], + introText: + '

Hong Kong is the largest financial hub in Asia and one of the safest and more convenient places to bank. Hong Kong banks are some of the most solvent and liquid banks worldwide.

\n

There are no exchange controls and accounts are available in multiple currencies, in addition to a large variety of investment and insurance products.

\n

Hong Kong banks are ideal for both individuals and businesses that require strong cash management services in various currencies and that have strong investment needs.

\n

Hong Kong is also the gateway to one of the largest and fastest-growing markets worldwide: China. Hong Kong banks offer RMB accounts and payment cards.

\n

Import/Export companies will have access to top trade finance services such as Letter of Credit and Bank guarantees.

\n

Hong Kong online businesses with HK bank accounts also have access to a broad range of merchant accounts and credit card processing aggregators.

\n

Hong Kong banks are also available for companies incorporated in tax-neutral jurisdictions. However, banks will want to see a solid business background, and a relatively low-risk commercial activity to onboard an offshore company.

\n

Offshore companies will need to provide enough supporting business documentation such as business plans, invoices, contracts, letters of intent, etc., to satisfy the bank’s compliance requirements.

\n

All in all, Hong Kong is a perfect banking location for local and international businesses, companies doing business in China and individuals looking for strong wealth management and investment services.

\n', + jurisdiction: { + businessAccounts: [ + 'Offshore Company', + 'Nonresident Onshore Company', + 'Resident Company', + 'Regional Company' + ], + countryCode: 'HK', + countryDetails: + '

Hong Kong is a Special Administrative Region of the People’s Republic of China (Hong Kong SAR). Its official languages are English and Cantonese.

\n

Although it is part of the People’s Republic of China, the region maintains an independent economic, administrative and judicial system, and even its own currency, system of customs and external borders.  Its official legal tender currency is the Hong Kong Dollar (HKD), pegged to the USD, which is the ninth most traded currency worldwide.

\n

The legislative council is the Hong Kong Parliament, which is formed by 60-members, half elected by universal suffrage in geographical circumscriptions, while the other 30 are elected by groups of representatives from different economic and social sectors.

\n

Its public finances are characterized by its sustainability, with no public net debt, continuous government surplus and ample foreign exchange reserves, all supported by rigorous anti-corruption measures.

\n

Hong Kong’s economy is mainly based on financial services, tourism, wholesale and retail trade, and international trade, especially trade between China and the rest of the world. Hong Kong is one of the world’s major financial hub, ranking eleventh worldwide in volume of banking operations and the Hong Kong Stock Exchange being the second largest capital market in Asia, after the Tokyo Stock Exchange.

', + countryName: 'Hong Kong', + goodFor: [ + 'Transactional Banking', + 'Credit Card Processing', + 'Payment Processors', + 'Private Banking', + 'Trade Finance' + ], + minDeposit: ['Low'], + payments: [ + 'PayPal', + 'Amazon Payouts', + 'Merchant Accounts', + 'Stripe', + 'Onshore CC Aggregator', + 'Prepaid / Credit Cards' + ], + personalAccounts: ['International'], + remote: ['In-Person'], + showApp: true, + wealthManagement: ['International'] + }, + minDeposit: 'HKD 1,000,000.00', + personalVisitRequired: true, + price: '1650', + priceOptions: '- Wealth Management Bank Account (1650)', + region: 'Hong Kong', + shop: 'https://flagtheory.com/product/open-a-bank-account-in-hong-kong/', + showApp: true, + showWallet: true, + templateId: '5d09d11c26f7be563f7e0650', + testDidAddress: '0xee10a3335f48e10b444e299cf017d57879109c1e32cec3e31103ceca7718d0ec', + testPrice: '0.25', + testTemplateId: '5d09d11c26f7be563f7e0650', + testWalletAddress: '0x23d233933c86f93b74705cf0d236b39f474249f8', + type: 'private', + walletAddress: '0x6ce3bdd91d3b9f55ec206970e75701043fba751d', + walletDescription: + '

Our banking support service is not just a mere introduction to the bank. We assist you in filling out the business questionnaires appropriately and help you understand and provide business details, commercial information and purpose/use of the bank account that a given bank wants to know in order to approve your account application. Banks want certainty and clarity on how the account will be used. Everything must be watertight. We will work with you to make sure there is minimal ‘back and forth’ and a smooth account opening process.

\n\n

Our banking support services include introductions to payment processors and merchant accounts to better support our e-commerce clients. Whether you just need standard credit card processing or specialized services for high-risk processing, we are happy to help you with introductions that can empower your business.

\n\n

\nBank Account opening requirements are subject to change at the discretion of the bank. There might be additional fees charged by the bank itself. Bank account opening is not guaranteed and is subject to the bank policies and compliance department. There might be restrictions on UBO nationalities, business activities and/or jurisdictions. A refund is guaranteed if the account is not successfully opened, but a 15% administrative fee applies.

' + }, + description: '', + env: 'development', + id: 322, + name: 'Hong Kong HK3b', + parentSku: null, + price: '0.25', + priceCurrency: 'USD', + sku: 'FT-BNK-HK3b', + status: 'active', + updatedAt: 1565097777686, + vendorId: 'flagtheory_banking' }, { - id: 15, - countryCode: 'kn', - region: 'Nevis', - eligibility: ['Resident Individuals', 'Regional Individuals', 'International Individuals'], - eligibilityExpanded: - 'Resident Individuals, Regional Individuals, International Individuals', - minInitialDeposit: 800, - minInitialDepositCurrency: 'USD', - goodFor: ['Transactional Banking', 'Multi-currency Cards'], - personalVisitRequired: false, - price: 200, - accountType: 'private', - currencies: ['USD, SGD, CAD'], - cards: ['Mastercard, Visa'], - timeToOpen: '1 Month', - onlineBanking: ['Internet Home Banking'] + category: 'banking', + createdAt: 1564997439862, + data: { + account: { + accountCode: 'HK1b', + accountTitle: 'Business Account', + bankCode: 'HK1bE', + bankName: 'Bank Of China (Hong Kong)', + cards: [ + 'UnionPay Debit (HKD)', + 'UnionPay Debit (CNY)', + 'Mastercard Credit Card (USD)', + 'Visa Credit (USD)' + ], + countryCode: 'HK', + countryName: 'Hong Kong', + currencies: ['HKD', 'USD', 'Multi-currency'], + details: + '

Any foreign business should have a Hong Kong business address (lease-agreement) in order to open an account. We can provide a Hong Kong business address for HKD 15,000 per annum. A Business connection with the region is required – via suppliers, client or company office, directors’ residency, or any other.

\n

Companies incorporated in tax-neutral jurisdictions (such as BVI, Cayman Islands, etc..) are eligible as long as they have a commercial activity and do business in Asia.

\n

Foreign companies engaging in high-risk businesses and/or conducting an activity which is regulated in Hong Kong (such as Money transmitter or Forex trading) are not eligible.

\n

There are no requirements in terms of business turnover or business size.

', + eligibility: 'Hong Kong Companies', + minAverageBalanceDescription: 'HKD 10,000.00', + minInitialDeposit: 'HKD 10,000.00', + minMonthlyBalance: 'HKD 10,000.00', + onboarding: + '
    \n
  • We will assist you in filling out the KYC and Business Questionnaires. In addition to your company and identity documents, you will need to provide certain business documentation to support your application such as invoices, letters of intent, contracts, etc.
  • \n
  • The Bank’s Relationship Manager will review your documentation. The banker may come back with additional questions or give green-light to your account opening process. This usually takes from 1 to 2 weeks.
  • \n
  • Once your account has been approved. We will arrange your appointment with the Relationship Manager in Hong Kong. The appointment is subject to the availability of the banker, and may be arranged in one or two weeks.
  • \n
  • Account signatories and directors will need to visit the Bank’s branch to provide original documents, have an interview with the banker and sign application forms.
  • \n
  • After 1 month, you will receive an e-mail from the bank confirming the account opening. You will receive your account details, internet banking credentials and ATM card.
  • \n
', + onlineBanking: ['Internet Banking', 'Mobile Banking'], + otherServices: [ + 'Trade Finance', + 'Cheque Book', + 'Payroll Services', + 'Investment Services', + 'Term-deposits' + ], + personalVisitRequired: true, + showApp: true, + showWallet: true, + templateId: '5d09d11c26f7be563f7e0650', + testTemplateId: '5d09d11c26f7be563f7e0650', + timeToOpen: '4-6 weeks' + }, + accountCode: 'HK1b', + activeTestPrice: true, + countryCode: 'HK', + eligibility: ['Offshore Companies', 'Resident Companies'], + goodFor: [ + 'Transactional Banking', + 'Credit Card Processing', + 'Payment Processors', + 'Private Banking', + 'Trade Finance' + ], + introText: + '

Hong Kong is the largest financial hub in Asia and one of the safest and more convenient places to bank. Hong Kong banks are some of the most solvent and liquid banks worldwide.

\n

There are no exchange controls and accounts are available in multiple currencies, in addition to a large variety of investment and insurance products.

\n

Hong Kong banks are ideal for both individuals and businesses that require strong cash management services in various currencies and that have strong investment needs.

\n

Hong Kong is also the gateway to one of the largest and fastest-growing markets worldwide: China. Hong Kong banks offer RMB accounts and payment cards.

\n

Import/Export companies will have access to top trade finance services such as Letter of Credit and Bank guarantees.

\n

Hong Kong online businesses with HK bank accounts also have access to a broad range of merchant accounts and credit card processing aggregators.

\n

Hong Kong banks are also available for companies incorporated in tax-neutral jurisdictions. However, banks will want to see a solid business background, and a relatively low-risk commercial activity to onboard an offshore company.

\n

Offshore companies will need to provide enough supporting business documentation such as business plans, invoices, contracts, letters of intent, etc., to satisfy the bank’s compliance requirements.

\n

All in all, Hong Kong is a perfect banking location for local and international businesses, companies doing business in China and individuals looking for strong wealth management and investment services.

\n', + jurisdiction: { + businessAccounts: [ + 'Offshore Company', + 'Nonresident Onshore Company', + 'Resident Company', + 'Regional Company' + ], + countryCode: 'HK', + countryDetails: + '

Hong Kong is a Special Administrative Region of the People’s Republic of China (Hong Kong SAR). Its official languages are English and Cantonese.

\n

Although it is part of the People’s Republic of China, the region maintains an independent economic, administrative and judicial system, and even its own currency, system of customs and external borders.  Its official legal tender currency is the Hong Kong Dollar (HKD), pegged to the USD, which is the ninth most traded currency worldwide.

\n

The legislative council is the Hong Kong Parliament, which is formed by 60-members, half elected by universal suffrage in geographical circumscriptions, while the other 30 are elected by groups of representatives from different economic and social sectors.

\n

Its public finances are characterized by its sustainability, with no public net debt, continuous government surplus and ample foreign exchange reserves, all supported by rigorous anti-corruption measures.

\n

Hong Kong’s economy is mainly based on financial services, tourism, wholesale and retail trade, and international trade, especially trade between China and the rest of the world. Hong Kong is one of the world’s major financial hub, ranking eleventh worldwide in volume of banking operations and the Hong Kong Stock Exchange being the second largest capital market in Asia, after the Tokyo Stock Exchange.

', + countryName: 'Hong Kong', + goodFor: [ + 'Transactional Banking', + 'Credit Card Processing', + 'Payment Processors', + 'Private Banking', + 'Trade Finance' + ], + minDeposit: ['Low'], + payments: [ + 'PayPal', + 'Amazon Payouts', + 'Merchant Accounts', + 'Stripe', + 'Onshore CC Aggregator', + 'Prepaid / Credit Cards' + ], + personalAccounts: ['International'], + remote: ['In-Person'], + showApp: true, + wealthManagement: ['International'] + }, + minDeposit: 'HKD 20,000.00', + personalVisitRequired: true, + price: '2050', + priceOptions: '- Corporate Bank Account (2050)', + region: 'Hong Kong', + shop: 'https://flagtheory.com/product/open-a-bank-account-in-hong-kong/', + showApp: true, + showWallet: true, + templateId: '5d09d11c26f7be563f7e0650', + testDidAddress: '0xee10a3335f48e10b444e299cf017d57879109c1e32cec3e31103ceca7718d0ec', + testPrice: '0.25', + testTemplateId: '5d09d11c26f7be563f7e0650', + testWalletAddress: '0x23d233933c86f93b74705cf0d236b39f474249f8', + type: 'business', + walletAddress: '0x6ce3bdd91d3b9f55ec206970e75701043fba751d', + walletDescription: + '

Our banking support service is not just a mere introduction to the bank. We assist you in filling out the business questionnaires appropriately and help you understand and provide business details, commercial information and purpose/use of the bank account that a given bank wants to know in order to approve your account application. Banks want certainty and clarity on how the account will be used. Everything must be watertight. We will work with you to make sure there is minimal ‘back and forth’ and a smooth account opening process.

\n\n

Our banking support services include introductions to payment processors and merchant accounts to better support our e-commerce clients. Whether you just need standard credit card processing or specialized services for high-risk processing, we are happy to help you with introductions that can empower your business.

\n\n

\nBank Account opening requirements are subject to change at the discretion of the bank. There might be additional fees charged by the bank itself. Bank account opening is not guaranteed and is subject to the bank policies and compliance department. There might be restrictions on UBO nationalities, business activities and/or jurisdictions. A refund is guaranteed if the account is not successfully opened, but a 15% administrative fee applies.

' + }, + description: '', + env: 'development', + id: 324, + name: 'Hong Kong HK1b', + parentSku: null, + price: '0.25', + priceCurrency: 'USD', + sku: 'FT-BNK-HK1b', + status: 'active', + updatedAt: 1565097777686, + vendorId: 'flagtheory_banking' } ]; diff --git a/stories/banking.stories.js b/stories/banking.stories.js index 57c465db0..98b6863a9 100644 --- a/stories/banking.stories.js +++ b/stories/banking.stories.js @@ -36,7 +36,7 @@ storiesOf('Banking', module)
From 34fba910423f02f0e3d5b5402a79052cec86af6a Mon Sep 17 00:00:00 2001 From: Eduardo Santiago Moura Date: Tue, 6 Aug 2019 20:49:48 -0300 Subject: [PATCH 002/207] fix(manage-applications): hotfix on update flow --- src/renderer/marketplace/incorporation/index.jsx | 1 - .../selfkey-id/main/components/selfkey-id-applications.jsx | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/renderer/marketplace/incorporation/index.jsx b/src/renderer/marketplace/incorporation/index.jsx index 77651b266..4ba9ec5e6 100644 --- a/src/renderer/marketplace/incorporation/index.jsx +++ b/src/renderer/marketplace/incorporation/index.jsx @@ -8,7 +8,6 @@ import { IncorporationsPaymentCompleteContainer } from './checkout/incorporation import { connect } from 'react-redux'; import { marketplaceOperations } from 'common/marketplace'; - class MarketplaceIncorporationComponent extends Component { async componentDidMount() { await this.props.dispatch(marketplaceOperations.loadMarketplaceOperation()); diff --git a/src/renderer/selfkey-id/main/components/selfkey-id-applications.jsx b/src/renderer/selfkey-id/main/components/selfkey-id-applications.jsx index 60df9f11d..7787777b6 100644 --- a/src/renderer/selfkey-id/main/components/selfkey-id-applications.jsx +++ b/src/renderer/selfkey-id/main/components/selfkey-id-applications.jsx @@ -430,12 +430,12 @@ class SelfkeyIdApplicationsComponent extends Component { }; handleApplicationRefresh = id => { - const { rp, afterAuthRoute } = this.props; + const { afterAuthRoute } = this.props; const cancelRoute = `/main/selfkeyId`; const authenticate = true; // if relying party not loaded, try again - if (!rp || !rp.authenticated) { + if (!this.state.refreshing) { this.setState({ loading: true, refreshing: true, applicationId: id }, async () => { await this.props.dispatch( kycOperations.loadRelyingParty( From b5acf05e98dc3894bedb89b81baaee316c0bdf72 Mon Sep 17 00:00:00 2001 From: Maxim Kovalov Date: Mon, 12 Aug 2019 12:07:22 +0300 Subject: [PATCH 003/207] feat(marketplace): update offers page --- .../marketplace/bank-accounts/list/offers-page.jsx | 4 ++-- stories/banking.stories.js | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/renderer/marketplace/bank-accounts/list/offers-page.jsx b/src/renderer/marketplace/bank-accounts/list/offers-page.jsx index 4ebc2de9b..17c8affca 100644 --- a/src/renderer/marketplace/bank-accounts/list/offers-page.jsx +++ b/src/renderer/marketplace/bank-accounts/list/offers-page.jsx @@ -39,7 +39,7 @@ const BankingOffersPage = withStyles(styles)( ({ classes, loading, - data, + inventory, keyRate, onDetails, accountType, @@ -93,7 +93,7 @@ const BankingOffersPage = withStyles(styles)( diff --git a/stories/banking.stories.js b/stories/banking.stories.js index 98b6863a9..0347fc8f9 100644 --- a/stories/banking.stories.js +++ b/stories/banking.stories.js @@ -97,7 +97,7 @@ storiesOf('Banking/OffersPage', module) .add('loading', () => ( ( bank.accountType === 'personal')} + inventory={bankingOffers.filter(bank => bank.data.type === 'personal')} accountType="personal" onAccountTypeChange={linkTo('Banking/OffersPage', accountType => accountType)} onDetails={linkTo('Banking/BankingDetailsPage', 'default')} @@ -116,8 +116,8 @@ storiesOf('Banking/OffersPage', module) .add('corporate', () => ( bank.accountType === 'business')} - accountType="corporate" + inventory={bankingOffers.filter(bank => bank.data.type === 'business')} + accountType="business" onAccountTypeChange={linkTo('Banking/OffersPage', accountType => accountType)} onDetails={linkTo('Banking/BankingDetailsPage', 'default')} onBackClick={action('banking offers page back')} @@ -126,7 +126,7 @@ storiesOf('Banking/OffersPage', module) .add('private', () => ( bank.accountType === 'private')} + inventory={bankingOffers.filter(bank => bank.data.type === 'private')} accountType="private" onAccountTypeChange={linkTo('Banking/OffersPage', accountType => accountType)} onDetails={linkTo('Banking/BankingDetailsPage', 'default')} From eae33329a51dd2c33093195e90dcb3597d8ca424 Mon Sep 17 00:00:00 2001 From: designhorf Date: Mon, 19 Aug 2019 16:41:11 +0200 Subject: [PATCH 004/207] feat: added Switch Account sidebar UI to stories --- .../wallet/main/sidebar-switch-account.jsx | 254 ++++++++++++++++++ stories/sidebar.stories.js | 7 + 2 files changed, 261 insertions(+) create mode 100644 src/renderer/wallet/main/sidebar-switch-account.jsx create mode 100644 stories/sidebar.stories.js diff --git a/src/renderer/wallet/main/sidebar-switch-account.jsx b/src/renderer/wallet/main/sidebar-switch-account.jsx new file mode 100644 index 000000000..f47514d39 --- /dev/null +++ b/src/renderer/wallet/main/sidebar-switch-account.jsx @@ -0,0 +1,254 @@ +import React, { Component } from 'react'; +import { + withStyles, + Button, + Drawer, + Grid, + List, + ListItem, + Typography, + Divider +} from '@material-ui/core'; +import Close from '@material-ui/icons/Close'; +import { SelfkeyLogo } from 'selfkey-ui'; +import PersonIcon from 'selfkey-ui/build/lib/icons/person'; +import CorporateIcon from 'selfkey-ui/build/lib/icons/corporate'; + +const styles = theme => ({ + list: { + justifyContent: 'space-between', + margin: 0, + minHeight: '100%', + overflow: 'auto', + width: 300 + }, + listItem: { + alignItems: 'end', + cursor: 'pointer', + display: 'flex', + paddingLeft: 0, + '&:hover': { + '& h6': { + transition: 'all 0.3s' + }, + '& p': { + color: '#ffffff', + transition: 'all 0.3s' + }, + '& svg': { + '& path': { + fill: '#ffffff', + transition: 'all 0.3s' + } + } + } + }, + logoSection: { + marginBottom: '30px', + marginTop: '-30px', + paddingLeft: '16px' + }, + logo: { + width: '38px', + height: '44px' + }, + logoText: { + fontFamily: 'Orbitron, arial, sans-serif', + fontSize: '18px', + letterSpacing: '2.77px', + lineHeight: '22px', + paddingTop: '3px' + }, + closeSection: { + width: '100%' + }, + pointer: { + cursor: 'pointer' + }, + secondaryButtons: { + alignItems: 'flex-end', + display: 'flex', + flexGrow: 2, + width: 'inherit' + }, + inheritWidth: { + width: 'inherit' + }, + inheritHeight: { + height: 'inherit' + }, + version: { + color: '#fff', + fontSize: '10px', + opacity: 0.6, + position: 'absolute', + right: 0, + width: 'auto' + }, + drawer: { + transition: 'all 3s', + '& > div:first-of-type': { + opacity: '1 !important' + } + }, + fullWidth: { + width: '100%' + }, + iconSpace: { + marginRight: '15px' + }, + gridBottomSpace: { + marginBottom: '20px' + }, + nameRole: { + display: 'flex', + flexDirection: 'column', + justifyContent: 'space-around' + } +}); + +const dataIDType = [ + { + name: 'Andrew Jones', + type: 'Personal' + }, + { + name: 'Andrew Jones US', + type: 'Personal' + }, + { + name: 'Google Inc', + type: 'Corporate' + } +]; + +const IDType = withStyles(styles)(({ dataIDType, classes }) => { + return ( + + {dataIDType.map((data, index) => { + return ( +
+ + + + {data.type === 'Personal' ? : } + + + {data.name} + + {data.type} + + + + + +
+ ); + })} +
+ ); +}); + +class SidebarSwitchAccount extends Component { + state = { + open: true + }; + + render() { + const { classes } = this.props; + + const sideList = ( + + + + + + + + + + + + + + + + SELFKEY + + + + + + + + Choose a SelfKey ID + + + + + + + + + + + + + + + + + + + + + + + + V {window.appVersion} + + + + + + ); + + return ( + +
+ {sideList} +
+
+ ); + } +} + +export default withStyles(styles)(SidebarSwitchAccount); diff --git a/stories/sidebar.stories.js b/stories/sidebar.stories.js new file mode 100644 index 000000000..6b2460f8a --- /dev/null +++ b/stories/sidebar.stories.js @@ -0,0 +1,7 @@ +import React from 'react'; +import { storiesOf } from '@storybook/react'; +import SidebarSwitchAccount from '../src/renderer/wallet/main/sidebar-switch-account'; + +storiesOf('Sidebars', module).add('CORP Sidebar Switch Account', () => ( + +)); From 2c180da34380c54e02803f490a918d11e98b14a5 Mon Sep 17 00:00:00 2001 From: Eduardo Santiago Moura Date: Mon, 19 Aug 2019 20:47:03 -0300 Subject: [PATCH 005/207] fix(address-book): remove duplicates --- src/renderer/address-book/main/index.jsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/renderer/address-book/main/index.jsx b/src/renderer/address-book/main/index.jsx index 8c1ffa2dd..b6a43dbac 100644 --- a/src/renderer/address-book/main/index.jsx +++ b/src/renderer/address-book/main/index.jsx @@ -37,6 +37,12 @@ const styles = theme => ({ } }); +function removeDuplicates(myArr, prop) { + return myArr.filter((obj, pos, arr) => { + return arr.map(mapObj => mapObj[prop]).indexOf(obj[prop]) === pos; + }); +} + class AddressBookContainer extends Component { state = { addresses: [] @@ -69,7 +75,7 @@ class AddressBookContainer extends Component { render() { const { classes } = this.props; - const { addresses } = this.state; + const addresses = removeDuplicates(this.state.addresses, 'address'); return ( Date: Tue, 20 Aug 2019 20:20:19 -0300 Subject: [PATCH 006/207] feat(marketplace): add not enough key validation --- .../incorporations-details-container.jsx | 23 +- .../details/incorporations-details-page.jsx | 223 ++++++++++-------- .../components/transaction-no-key-error.jsx | 6 +- 3 files changed, 148 insertions(+), 104 deletions(-) diff --git a/src/renderer/marketplace/incorporation/details/incorporations-details-container.jsx b/src/renderer/marketplace/incorporation/details/incorporations-details-container.jsx index 9b1233ffc..9bfe1472e 100644 --- a/src/renderer/marketplace/incorporation/details/incorporations-details-container.jsx +++ b/src/renderer/marketplace/incorporation/details/incorporations-details-container.jsx @@ -9,15 +9,22 @@ import { walletSelectors } from 'common/wallet'; import { withStyles } from '@material-ui/core/styles'; import { incorporationsSelectors, incorporationsOperations } from 'common/incorporations'; import { IncorporationsDetailsPage } from './incorporations-details-page'; +import config from 'common/config'; const styles = theme => ({}); class IncorporationsDetailsContainer extends MarketplaceIncorporationsComponent { state = { tab: 'description', - loading: false + loading: false, + cryptoValue: 0 }; + constructor() { + super(); + this.handleCryptoValueChange = this.handleCryptoValueChange.bind(this); + } + async componentDidMount() { const { program } = this.props; @@ -103,11 +110,12 @@ class IncorporationsDetailsContainer extends MarketplaceIncorporationsComponent }; onApplyClick = () => { - const { rp, wallet } = this.props; + const { rp, wallet, program } = this.props; const selfkeyIdRequiredRoute = '/main/marketplace-selfkey-id-required'; const selfkeyDIDRequiredRoute = '/main/marketplace-selfkey-did-required'; + const transactionNoKeyError = '/main/transaction-no-key-error'; const authenticated = true; - + const price = program.price; // When clicking the start process, // we check if an authenticated kyc-chain session exists // If it doesn't we trigger a new authenticated rp session @@ -120,6 +128,9 @@ class IncorporationsDetailsContainer extends MarketplaceIncorporationsComponent if (!wallet.did) { return this.props.dispatch(push(selfkeyDIDRequiredRoute)); } + if (price > this.state.cryptoValue) { + return this.props.dispatch(push(transactionNoKeyError)); + } if (!rp || !rp.authenticated) { await this.props.dispatch( kycOperations.loadRelyingParty( @@ -135,6 +146,10 @@ class IncorporationsDetailsContainer extends MarketplaceIncorporationsComponent }); }; + handleCryptoValueChange = cryptoValue => { + this.setState({ cryptoValue: Number(cryptoValue) }); + }; + render() { const { program, keyRate, kycRequirements, country, treaties } = this.props; const { templateId } = this.props.match.params; @@ -161,6 +176,8 @@ class IncorporationsDetailsContainer extends MarketplaceIncorporationsComponent templateId={templateId} onBack={this.onBackClick} onStatusAction={this.onStatusActionClick} + cryptoCurrency={config.constants.primaryToken} + cryptoValueChange={this.handleCryptoValueChange} /> ); } diff --git a/src/renderer/marketplace/incorporation/details/incorporations-details-page.jsx b/src/renderer/marketplace/incorporation/details/incorporations-details-page.jsx index 3a9b43b37..27a04b10a 100644 --- a/src/renderer/marketplace/incorporation/details/incorporations-details-page.jsx +++ b/src/renderer/marketplace/incorporation/details/incorporations-details-page.jsx @@ -1,10 +1,14 @@ -import React from 'react'; +import React, { Component } from 'react'; import { withStyles } from '@material-ui/core/styles'; import { Grid, Button, Typography } from '@material-ui/core'; import { ApplicationStatusBar } from '../../../kyc/application/application-status'; import { CertificateIcon } from 'selfkey-ui'; import { FlagCountryName, ResumeBox, ProgramPrice, MarketplaceKycRequirements } from '../../common'; import { IncorporationsDetailsTabs } from './incorporations-details-tabs'; +import { connect } from 'react-redux'; +import { getLocale } from 'common/locale/selectors'; +import { getFiatCurrency } from 'common/fiatCurrency/selectors'; +import { getCryptoValue, getToValue } from '../../../common/price-utils'; const styles = theme => ({ container: { @@ -91,114 +95,137 @@ export const IncorporationsApplicationButton = withStyles(styles)( ) ); -export const IncorporationsDetailsPage = withStyles(styles)(props => { - const { - classes, - applicationStatus, - countryCode, - region, - contact, - resume, - onStatusAction, - onBack, - loading, - canIncorporate, - startApplication, - keyRate, - price, - tab, - kycRequirements, - templateId, - onTabChange - } = props; - return ( - - -
- -
-
- - -
- +class IncorporationsDetails extends Component { + componentDidMount() { + this.props.cryptoValueChange(this.props.cryptoValue); + } + + render() { + const { + classes, + applicationStatus, + countryCode, + region, + contact, + resume, + onStatusAction, + onBack, + loading, + canIncorporate, + startApplication, + keyRate, + price, + tab, + kycRequirements, + templateId, + onTabChange + } = this.props; + return ( + + +
+
- - {region} -
- - + - - - - - - - - +
+ +
+ + {region} + +
+ + + + + + + + + + + + - - - - - - + + + + + +
-
- ); -}); + ); + } +} + +const mapStateToProps = (state, props) => { + return { + ...getLocale(state), + toCurrency: getFiatCurrency(state).fiatCurrency, + cryptoValue: getCryptoValue(state, props), + toValue: getToValue(state, props) + }; +}; + +export const IncorporationsDetailsPage = connect(mapStateToProps)( + withStyles(styles)(IncorporationsDetails) +); export default IncorporationsDetailsPage; diff --git a/src/renderer/transaction/transaction-no-key-error/components/transaction-no-key-error.jsx b/src/renderer/transaction/transaction-no-key-error/components/transaction-no-key-error.jsx index c3e782453..c46e04518 100644 --- a/src/renderer/transaction/transaction-no-key-error/components/transaction-no-key-error.jsx +++ b/src/renderer/transaction/transaction-no-key-error/components/transaction-no-key-error.jsx @@ -24,9 +24,9 @@ export const TransactionNoKeyError = withStyles(styles)(
- You do not have enough KEY tokens to pay for the incorporation. Please - transfer some KEY to this address and try again. Your KEY address of this - wallet is listed below. + You do not have enough KEY tokens to pay for this Marketplace Application. + Please transfer some KEY to this address and try again. Your KEY address of + this wallet is listed below.
From 4f3d3c82b84fe875953dd1f56a5459dc3e4ece6c Mon Sep 17 00:00:00 2001 From: Eduardo Santiago Moura Date: Tue, 20 Aug 2019 23:00:29 -0300 Subject: [PATCH 007/207] feat(marketplace): update validation and message --- .../details/incorporations-details-container.jsx | 7 ++++--- src/renderer/transaction/common/transaction-error-box.jsx | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/renderer/marketplace/incorporation/details/incorporations-details-container.jsx b/src/renderer/marketplace/incorporation/details/incorporations-details-container.jsx index 9bfe1472e..8e0de543f 100644 --- a/src/renderer/marketplace/incorporation/details/incorporations-details-container.jsx +++ b/src/renderer/marketplace/incorporation/details/incorporations-details-container.jsx @@ -110,12 +110,13 @@ class IncorporationsDetailsContainer extends MarketplaceIncorporationsComponent }; onApplyClick = () => { - const { rp, wallet, program } = this.props; + const { rp, wallet, program, keyRate } = this.props; const selfkeyIdRequiredRoute = '/main/marketplace-selfkey-id-required'; const selfkeyDIDRequiredRoute = '/main/marketplace-selfkey-did-required'; const transactionNoKeyError = '/main/transaction-no-key-error'; const authenticated = true; - const price = program.price; + const keyPrice = program.price / keyRate; + const keyAvailable = this.state.cryptoValue; // When clicking the start process, // we check if an authenticated kyc-chain session exists // If it doesn't we trigger a new authenticated rp session @@ -128,7 +129,7 @@ class IncorporationsDetailsContainer extends MarketplaceIncorporationsComponent if (!wallet.did) { return this.props.dispatch(push(selfkeyDIDRequiredRoute)); } - if (price > this.state.cryptoValue) { + if (keyPrice > keyAvailable) { return this.props.dispatch(push(transactionNoKeyError)); } if (!rp || !rp.authenticated) { diff --git a/src/renderer/transaction/common/transaction-error-box.jsx b/src/renderer/transaction/common/transaction-error-box.jsx index e4c419c08..ae56241bc 100644 --- a/src/renderer/transaction/common/transaction-error-box.jsx +++ b/src/renderer/transaction/common/transaction-error-box.jsx @@ -7,7 +7,7 @@ const styles = theme => ({}); export const TransactionErrorBox = withStyles(styles)( ({ children, publicKey, closeAction, open = true, subtitle }) => ( - + From 57aff96df0e45502521bd9dca210540adf964fb6 Mon Sep 17 00:00:00 2001 From: Eduardo Santiago Moura Date: Tue, 20 Aug 2019 23:42:41 -0300 Subject: [PATCH 008/207] feat(marketplace): add validation on bank accounts --- .../details/details-container.jsx | 24 +- .../bank-accounts/details/details-page.jsx | 221 ++++++++++-------- 2 files changed, 144 insertions(+), 101 deletions(-) diff --git a/src/renderer/marketplace/bank-accounts/details/details-container.jsx b/src/renderer/marketplace/bank-accounts/details/details-container.jsx index 1381c9bdb..19d6a271a 100644 --- a/src/renderer/marketplace/bank-accounts/details/details-container.jsx +++ b/src/renderer/marketplace/bank-accounts/details/details-container.jsx @@ -10,6 +10,7 @@ import { withStyles } from '@material-ui/core/styles'; import { bankAccountsOperations, bankAccountsSelectors } from 'common/bank-accounts'; import { BankingDetailsPage } from './details-page'; import { incorporationsOperations, incorporationsSelectors } from 'common/incorporations'; +import config from 'common/config'; const styles = theme => ({}); const MARKETPLACE_BANK_ACCOUNTS_ROOT_PATH = '/main/marketplace-bank-accounts'; @@ -17,9 +18,15 @@ const MARKETPLACE_BANK_ACCOUNTS_ROOT_PATH = '/main/marketplace-bank-accounts'; class BankAccountsDetailContainer extends MarketplaceBankAccountsComponent { state = { tab: 'types', - loading: false + loading: false, + cryptoValue: 0 }; + constructor() { + super(); + this.handleCryptoValueChange = this.handleCryptoValueChange.bind(this); + } + async componentDidMount() { const { accountType, country } = this.props; @@ -75,11 +82,13 @@ class BankAccountsDetailContainer extends MarketplaceBankAccountsComponent { }; onApplyClick = () => { - const { rp, wallet } = this.props; + const { rp, wallet, accountType, keyRate } = this.props; const selfkeyIdRequiredRoute = '/main/marketplace-selfkey-id-required'; const selfkeyDIDRequiredRoute = '/main/marketplace-selfkey-did-required'; + const transactionNoKeyError = '/main/transaction-no-key-error'; const authenticated = true; - + const keyPrice = accountType.price / keyRate; + const keyAvailable = this.state.cryptoValue; // When clicking the start process, // we check if an authenticated kyc-chain session exists // If it doesn't we trigger a new authenticated rp session @@ -92,6 +101,9 @@ class BankAccountsDetailContainer extends MarketplaceBankAccountsComponent { if (!wallet.did) { return this.props.dispatch(push(selfkeyDIDRequiredRoute)); } + if (keyPrice > keyAvailable) { + return this.props.dispatch(push(transactionNoKeyError)); + } if (!rp || !rp.authenticated) { await this.props.dispatch( kycOperations.loadRelyingParty( @@ -143,6 +155,10 @@ class BankAccountsDetailContainer extends MarketplaceBankAccountsComponent { ]; }; + handleCryptoValueChange = cryptoValue => { + this.setState({ cryptoValue: Number(cryptoValue) }); + }; + render() { const { accountType, banks, keyRate, jurisdiction, kycRequirements, country } = this.props; const { price, countryCode, region } = accountType; @@ -167,6 +183,8 @@ class BankAccountsDetailContainer extends MarketplaceBankAccountsComponent { templateId={this.props.match.params.templateId} onBack={this.onBackClick} onStatusAction={this.onStatusActionClick} + cryptoCurrency={config.constants.primaryToken} + cryptoValueChange={this.handleCryptoValueChange} /> ); } diff --git a/src/renderer/marketplace/bank-accounts/details/details-page.jsx b/src/renderer/marketplace/bank-accounts/details/details-page.jsx index b26456cd2..c43fa82c4 100644 --- a/src/renderer/marketplace/bank-accounts/details/details-page.jsx +++ b/src/renderer/marketplace/bank-accounts/details/details-page.jsx @@ -1,10 +1,14 @@ -import React from 'react'; +import React, { Component } from 'react'; import { withStyles } from '@material-ui/core/styles'; import { Grid, Button, Typography } from '@material-ui/core'; import { ApplicationStatusBar } from '../../../kyc/application/application-status'; import { MoneyIcon } from 'selfkey-ui'; import { FlagCountryName, ResumeBox, ProgramPrice, MarketplaceKycRequirements } from '../../common'; import { BankingDetailsPageTabs } from './details-tabs'; +import { connect } from 'react-redux'; +import { getLocale } from 'common/locale/selectors'; +import { getFiatCurrency } from 'common/fiatCurrency/selectors'; +import { getCryptoValue, getToValue } from '../../../common/price-utils'; const styles = theme => ({ container: { @@ -91,114 +95,135 @@ export const BankingApplicationButton = withStyles(styles)( ) ); -export const BankingDetailsPage = withStyles(styles)(props => { - const { - classes, - applicationStatus, - countryCode, - region, - contact, - onStatusAction, - onBack, - loading, - canOpenBankAccount, - resume = [], - startApplication, - keyRate, - price, - tab, - kycRequirements, - templateId, - onTabChange - } = props; - return ( - - -
- -
-
- - -
- +class BankingDetails extends Component { + componentDidMount() { + this.props.cryptoValueChange(this.props.cryptoValue); + } + + render() { + const { + classes, + applicationStatus, + countryCode, + region, + contact, + onStatusAction, + onBack, + loading, + canOpenBankAccount, + resume = [], + startApplication, + keyRate, + price, + tab, + kycRequirements, + templateId, + onTabChange + } = this.props; + return ( + + +
+
- - {region} -
- - + - - - - - - - - +
+ +
+ + {region} + +
+ + + + + + + + + + + + - - - - - - + + + + + +
-
- ); -}); + ); + } +} + +const mapStateToProps = (state, props) => { + return { + ...getLocale(state), + toCurrency: getFiatCurrency(state).fiatCurrency, + cryptoValue: getCryptoValue(state, props), + toValue: getToValue(state, props) + }; +}; + +export const BankingDetailsPage = connect(mapStateToProps)(withStyles(styles)(BankingDetails)); export default BankingDetailsPage; From 95fb4f5d8e684026832ee6cf1ca83ba8d8ba489d Mon Sep 17 00:00:00 2001 From: designhorf Date: Thu, 22 Aug 2019 17:56:16 +0200 Subject: [PATCH 009/207] feat: added new logos to Sidebar --- src/renderer/wallet/main/sidebar.jsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/renderer/wallet/main/sidebar.jsx b/src/renderer/wallet/main/sidebar.jsx index 6c23e0590..893cc006e 100644 --- a/src/renderer/wallet/main/sidebar.jsx +++ b/src/renderer/wallet/main/sidebar.jsx @@ -16,7 +16,10 @@ import { MarketplaceMenuIcon, SelfkeyIDMenuIcon, AddressBookMenuIcon, - SelfkeyLogo + SelfkeyLogo, + MenuHelpIcon, + SwitchAccountsIcon, + PowerIcon } from 'selfkey-ui'; const styles = theme => ({ From cbfddd94420cc01a42c3e4a62f7e48d84d4ee39e Mon Sep 17 00:00:00 2001 From: designhorf Date: Thu, 22 Aug 2019 17:58:33 +0200 Subject: [PATCH 010/207] feat: added home link to SK logo --- src/renderer/wallet/main/sidebar.jsx | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/renderer/wallet/main/sidebar.jsx b/src/renderer/wallet/main/sidebar.jsx index 893cc006e..f69d13333 100644 --- a/src/renderer/wallet/main/sidebar.jsx +++ b/src/renderer/wallet/main/sidebar.jsx @@ -160,16 +160,15 @@ class Sidebar extends Component { spacing={16} className={classes.logoSection} > - + - - - - SELFKEY - - + + + SELFKEY +
+
Date: Thu, 22 Aug 2019 18:01:03 +0200 Subject: [PATCH 011/207] feat: added new icons to bottom menu items --- src/renderer/wallet/main/sidebar.jsx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/renderer/wallet/main/sidebar.jsx b/src/renderer/wallet/main/sidebar.jsx index f69d13333..6ecdf03d8 100644 --- a/src/renderer/wallet/main/sidebar.jsx +++ b/src/renderer/wallet/main/sidebar.jsx @@ -234,6 +234,9 @@ class Sidebar extends Component { }} key="helpAndSupport" > + + + Help & Support @@ -243,11 +246,17 @@ class Sidebar extends Component { component={switchAccount} key="switchAccount" > + + + Switch Accounts + + + Quit From 7bca611a50062b20096998bac92fd6ab065d625e Mon Sep 17 00:00:00 2001 From: designhorf Date: Thu, 22 Aug 2019 18:06:20 +0200 Subject: [PATCH 012/207] feat: always visible Sidebar with animation --- src/renderer/wallet/main/sidebar.jsx | 32 ++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/src/renderer/wallet/main/sidebar.jsx b/src/renderer/wallet/main/sidebar.jsx index 6ecdf03d8..a6e2ba13c 100644 --- a/src/renderer/wallet/main/sidebar.jsx +++ b/src/renderer/wallet/main/sidebar.jsx @@ -99,8 +99,33 @@ const styles = theme => ({ drawer: { transition: 'all 3s', '& > div:first-of-type': { - opacity: '1 !important' + left: 0, + opacity: '1 !important', + right: 'auto' } + }, + openedDrawer: { + '& > div:first-of-type': { + minWidth: 200, + transition: 'all 0.2s ease-out' + }, + '& .sidebarContainer': { + transition: 'all 0.2s ease-out', + width: 200 + } + }, + closedDrawer: { + '& > div:first-of-type': { + minWidth: 56, + transition: 'all 0.2s ease-out' + }, + '& .sidebarContainer': { + transition: 'all 0.2s ease-out', + width: 56 + } + }, + listItemIcon: { + marginRight: '22px' } }); @@ -276,7 +301,10 @@ class Sidebar extends Component { anchor="right" open={this.state.open} onClose={() => this.toggleDrawer(false)} - className={classes.drawer} + className={`${classes.drawer} ${ + this.state.open ? classes.openedDrawer : classes.closedDrawer + }`} + variant="permanent" >
Date: Thu, 22 Aug 2019 18:07:51 +0200 Subject: [PATCH 013/207] fix: reduced size of logo and logo text --- src/renderer/wallet/main/sidebar.jsx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/renderer/wallet/main/sidebar.jsx b/src/renderer/wallet/main/sidebar.jsx index a6e2ba13c..f3a771f4a 100644 --- a/src/renderer/wallet/main/sidebar.jsx +++ b/src/renderer/wallet/main/sidebar.jsx @@ -36,15 +36,16 @@ const styles = theme => ({ paddingLeft: '16px' }, logo: { - width: '38px', - height: '44px' + width: '30px', + height: '34px' }, logoText: { fontFamily: 'Orbitron, arial, sans-serif', - fontSize: '18px', + fontSize: '16px', letterSpacing: '2.77px', lineHeight: '22px', - paddingTop: '3px' + marginLeft: '13px', + marginTop: '3px' }, closeSection: { width: '100%' From 1f0fc4ddd90e27cdb63f3e8544072657f187df86 Mon Sep 17 00:00:00 2001 From: designhorf Date: Thu, 22 Aug 2019 18:12:52 +0200 Subject: [PATCH 014/207] fix: alignment of Sidebar --- src/renderer/wallet/main/sidebar.jsx | 80 ++++++++++++++++++---------- 1 file changed, 51 insertions(+), 29 deletions(-) diff --git a/src/renderer/wallet/main/sidebar.jsx b/src/renderer/wallet/main/sidebar.jsx index f3a771f4a..e4eff26f2 100644 --- a/src/renderer/wallet/main/sidebar.jsx +++ b/src/renderer/wallet/main/sidebar.jsx @@ -10,7 +10,6 @@ import { Divider } from '@material-ui/core'; import { Link } from 'react-router-dom'; -import Close from '@material-ui/icons/Close'; import { DashboardMenuIcon, MarketplaceMenuIcon, @@ -28,12 +27,11 @@ const styles = theme => ({ margin: 0, minHeight: '100%', overflow: 'auto', - width: 300 + width: '100%' }, logoSection: { marginBottom: '30px', - marginTop: '-30px', - paddingLeft: '16px' + marginTop: '-30px' }, logo: { width: '30px', @@ -53,12 +51,22 @@ const styles = theme => ({ pointer: { cursor: 'pointer' }, + link: { + outline: 'none', + '&:focus': { + outline: 'none' + } + }, listItem: { - alignItems: 'end', cursor: 'pointer', display: 'flex', marginBottom: '30px', paddingLeft: '10px', + '& p': { + overflow: 'hidden', + textOverflow: 'ellipsis', + whiteSpace: 'nowrap' + }, '&:hover': { color: '#ffffff', '& p': { @@ -167,24 +175,16 @@ class Sidebar extends Component { direction="column" justify="flex-start" alignItems="flex-start" - className={classes.list} + className={`${classes.list} sidebarContainer`} spacing={40} > - - - - - - - - + @@ -194,16 +194,16 @@ class Sidebar extends Component { - - - + + + - - + + Dashboard @@ -215,24 +215,46 @@ class Sidebar extends Component { component={marketplace} key="marketplace" > - - + + Marketplace + + + + + + Address Book + + + - - + + - SelfKey ID + My Profile - - + + { From db9ab21f442a89553ceeece62fc4d20164e71c42 Mon Sep 17 00:00:00 2001 From: designhorf Date: Thu, 22 Aug 2019 18:14:47 +0200 Subject: [PATCH 015/207] feat: commented out new menu item --- src/renderer/wallet/main/sidebar.jsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/renderer/wallet/main/sidebar.jsx b/src/renderer/wallet/main/sidebar.jsx index e4eff26f2..da4f5bdce 100644 --- a/src/renderer/wallet/main/sidebar.jsx +++ b/src/renderer/wallet/main/sidebar.jsx @@ -257,19 +257,19 @@ class Sidebar extends Component { My Profile - - - + + - Address Book + Affiliate Program - + */} From 246c58364dfbd56da431714f530b64c59a2106cb Mon Sep 17 00:00:00 2001 From: designhorf Date: Thu, 22 Aug 2019 18:17:50 +0200 Subject: [PATCH 016/207] feat: added new Menu icon --- src/renderer/wallet/main/toolbar.jsx | 65 ++++++++-------------------- 1 file changed, 18 insertions(+), 47 deletions(-) diff --git a/src/renderer/wallet/main/toolbar.jsx b/src/renderer/wallet/main/toolbar.jsx index ef0d0ebdb..7b130f45f 100644 --- a/src/renderer/wallet/main/toolbar.jsx +++ b/src/renderer/wallet/main/toolbar.jsx @@ -1,7 +1,6 @@ import React, { Component } from 'react'; -import { withStyles, Grid, IconButton } from '@material-ui/core'; -import { SelfkeyLogo, MenuButtonIcon } from 'selfkey-ui'; -import { Link } from 'react-router-dom'; +import { withStyles, Grid } from '@material-ui/core'; +import { MenuNewIcon } from 'selfkey-ui'; import PriceBox from '../../price-box'; import Sidebar from './sidebar'; import config from 'common/config'; @@ -12,7 +11,6 @@ const styles = theme => ({ boxShadow: 'inset 0 -1px 0 0 #475768, 1px 0 0 0 rgba(118,128,147,0.2), 2px 0 2px 0 rgba(0,0,0,0.2)' }, - logo: { width: '38px', height: '44px', @@ -27,29 +25,22 @@ const styles = theme => ({ '-webkit-transform': 'rotate(90deg)' } }, - link: { outline: 'none', '&:focus': { outline: 'none' } }, - - sepVertContainer: { - display: 'flex', - justifyContent: 'space-around' + menuIcon: { + '&:hover': { + cursor: 'pointer' + } }, - - sepVert: { - background: 'linear-gradient(180deg, rgba(94, 11, 128, 0) 0%, #475768 100%)', - height: '59px', - marginTop: '16px', - width: '1px' + openedDrawer: { + left: '220px' }, - - menuButton: { - width: '30px', - height: '30px' + closedDrawer: { + left: '77px' } }); @@ -69,6 +60,13 @@ class Toolbar extends Component { return (
+ this.toggleDrawer(!this.state.isSidebarOpen)} + /> - - - - - - + @@ -91,28 +84,6 @@ class Toolbar extends Component { - - - -
- - - - this.toggleDrawer(true)} - /> - - - -
); From c5d08573317377a721d03aa376d52938c22837fa Mon Sep 17 00:00:00 2001 From: designhorf Date: Thu, 22 Aug 2019 18:23:33 +0200 Subject: [PATCH 017/207] feat: updated for latest Selfkey UI --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index aea8fae20..a5e2c319e 100644 --- a/package.json +++ b/package.json @@ -113,7 +113,7 @@ "reselect": "4.0.0", "sanitize-html": "1.20.0", "scrypt": "6.0.3", - "selfkey-ui": "https://github.com/SelfKeyFoundation/selfkey-ui.git#c5cfa0773a30dbdae0f676d4c52e90b50009d840", + "selfkey-ui": "https://github.com/SelfKeyFoundation/selfkey-ui.git#b81ef4db93508276e0d8ed42bbef54dc724c3947", "selfkey.js": "1.0.24", "serialize-error": "3.0.0", "snyk": "1.216.0", From 687c46fe802a5f128c51e81dd76408658641d745 Mon Sep 17 00:00:00 2001 From: designhorf Date: Mon, 26 Aug 2019 10:12:26 +0200 Subject: [PATCH 018/207] feat: latest Selfkey UI --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a5e2c319e..a11175c2e 100644 --- a/package.json +++ b/package.json @@ -113,7 +113,7 @@ "reselect": "4.0.0", "sanitize-html": "1.20.0", "scrypt": "6.0.3", - "selfkey-ui": "https://github.com/SelfKeyFoundation/selfkey-ui.git#b81ef4db93508276e0d8ed42bbef54dc724c3947", + "selfkey-ui": "https://github.com/SelfKeyFoundation/selfkey-ui.git#33cc0ebbb5d8ac4689b541a7ba143db5030654d3", "selfkey.js": "1.0.24", "serialize-error": "3.0.0", "snyk": "1.216.0", From fc749ea6218d4236dfcf1b8af71fe94b5c77c5f6 Mon Sep 17 00:00:00 2001 From: designhorf Date: Mon, 26 Aug 2019 11:10:46 +0200 Subject: [PATCH 019/207] fix: same color for all menu items --- src/renderer/wallet/main/sidebar.jsx | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/src/renderer/wallet/main/sidebar.jsx b/src/renderer/wallet/main/sidebar.jsx index da4f5bdce..748958d27 100644 --- a/src/renderer/wallet/main/sidebar.jsx +++ b/src/renderer/wallet/main/sidebar.jsx @@ -90,13 +90,6 @@ const styles = theme => ({ inheritHeight: { height: 'inherit' }, - textColor: { - color: '#fff', - opacity: 0.8, - '&:hover': { - opacity: 1 - } - }, version: { color: '#fff', fontSize: '10px', @@ -285,7 +278,7 @@ class Sidebar extends Component { - + Help & Support @@ -297,15 +290,15 @@ class Sidebar extends Component { - - Switch Accounts + + Switch Wallet - + Quit From 54cb3e09e468674c66fe248d02f790732041339b Mon Sep 17 00:00:00 2001 From: designhorf Date: Mon, 26 Aug 2019 11:16:25 +0200 Subject: [PATCH 020/207] fix: alignment of version --- src/renderer/wallet/main/sidebar.jsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/renderer/wallet/main/sidebar.jsx b/src/renderer/wallet/main/sidebar.jsx index 748958d27..793502c8b 100644 --- a/src/renderer/wallet/main/sidebar.jsx +++ b/src/renderer/wallet/main/sidebar.jsx @@ -95,9 +95,11 @@ const styles = theme => ({ fontSize: '10px', opacity: 0.6, position: 'absolute', - right: 0, width: 'auto' }, + versionWrap: { + paddingLeft: '50px' + }, drawer: { transition: 'all 3s', '& > div:first-of-type': { @@ -302,7 +304,7 @@ class Sidebar extends Component { Quit - + V {window.appVersion} From 016b3a6fce7c1b72b33e02af7f1a68ca87b3be33 Mon Sep 17 00:00:00 2001 From: designhorf Date: Mon, 26 Aug 2019 11:22:55 +0200 Subject: [PATCH 021/207] fix: commented out Export Wallet menu item --- src/renderer/wallet/main/sidebar.jsx | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/renderer/wallet/main/sidebar.jsx b/src/renderer/wallet/main/sidebar.jsx index 793502c8b..4ce992277 100644 --- a/src/renderer/wallet/main/sidebar.jsx +++ b/src/renderer/wallet/main/sidebar.jsx @@ -19,6 +19,8 @@ import { MenuHelpIcon, SwitchAccountsIcon, PowerIcon + // MenuAffiliateIcon, + // MenuExportIcon } from 'selfkey-ui'; const styles = theme => ({ @@ -259,7 +261,7 @@ class Sidebar extends Component { key="affiliate" > - + Affiliate Program @@ -284,6 +286,18 @@ class Sidebar extends Component { Help & Support + {/* + + + + + Export Wallet + + */} Date: Mon, 26 Aug 2019 11:26:58 +0200 Subject: [PATCH 022/207] fix: hover state of svg icon --- src/renderer/wallet/main/sidebar.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/renderer/wallet/main/sidebar.jsx b/src/renderer/wallet/main/sidebar.jsx index 4ce992277..6e5e35b70 100644 --- a/src/renderer/wallet/main/sidebar.jsx +++ b/src/renderer/wallet/main/sidebar.jsx @@ -76,6 +76,7 @@ const styles = theme => ({ }, '& svg': { color: '#ffffff', + fill: '#ffffff', stroke: '#ffffff' } } From 4a2fa2a533b7ce17b1df1cbc14aa2b2fe424becf Mon Sep 17 00:00:00 2001 From: designhorf Date: Mon, 26 Aug 2019 11:29:52 +0200 Subject: [PATCH 023/207] feat: width of opened and closed divider w/ transition --- src/renderer/wallet/main/sidebar.jsx | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/renderer/wallet/main/sidebar.jsx b/src/renderer/wallet/main/sidebar.jsx index 6e5e35b70..69636b121 100644 --- a/src/renderer/wallet/main/sidebar.jsx +++ b/src/renderer/wallet/main/sidebar.jsx @@ -119,6 +119,13 @@ const styles = theme => ({ '& .sidebarContainer': { transition: 'all 0.2s ease-out', width: 200 + }, + '& .divider': { + marginBottom: '30px', + marginLeft: 9, + paddingLeft: 0, + transition: 'all 0.2s ease-out', + width: 160 } }, closedDrawer: { @@ -129,6 +136,13 @@ const styles = theme => ({ '& .sidebarContainer': { transition: 'all 0.2s ease-out', width: 56 + }, + '& .divider': { + marginBottom: '30px', + marginLeft: 9, + paddingLeft: 0, + transition: 'all 0.2s ease-out', + width: 16 } }, listItemIcon: { @@ -241,7 +255,7 @@ class Sidebar extends Component { Address Book - + */} +
From 910bc30dbdd184439eeac102fb2c4d8a00ac98f3 Mon Sep 17 00:00:00 2001 From: designhorf Date: Mon, 26 Aug 2019 11:31:55 +0200 Subject: [PATCH 024/207] feat: added basic switching profile to toolbar --- src/renderer/wallet/main/toolbar.jsx | 53 ++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/src/renderer/wallet/main/toolbar.jsx b/src/renderer/wallet/main/toolbar.jsx index 7b130f45f..49352081b 100644 --- a/src/renderer/wallet/main/toolbar.jsx +++ b/src/renderer/wallet/main/toolbar.jsx @@ -1,6 +1,6 @@ import React, { Component } from 'react'; -import { withStyles, Grid } from '@material-ui/core'; -import { MenuNewIcon } from 'selfkey-ui'; +import { withStyles, Grid, Typography } from '@material-ui/core'; +import { MenuNewIcon, DropdownIcon, PersonIcon } from 'selfkey-ui'; import PriceBox from '../../price-box'; import Sidebar from './sidebar'; import config from 'common/config'; @@ -41,6 +41,24 @@ const styles = theme => ({ }, closedDrawer: { left: '77px' + }, + nameRole: { + display: 'flex', + flexDirection: 'column', + justifyContent: 'space-around', + margin: '0 20px 0 15px', + maxWidth: '118px' + }, + sepVertContainer: { + display: 'flex', + justifyContent: 'space-around', + marginRight: '20px' + }, + sepVert: { + background: 'linear-gradient(180deg, rgba(94, 11, 128, 0) 0%, #475768 100%)', + height: '59px', + marginTop: '16px', + width: '1px' } }); @@ -74,7 +92,7 @@ class Toolbar extends Component { alignItems="center" className={classes.wrapper} > - + @@ -83,6 +101,35 @@ class Toolbar extends Component { + {/* +
+ */} + + + + + + + + + + Name + + Personal Profile + + + + + + + +
From 379d19b285928b50792cc74d3a3a67e27dd7217f Mon Sep 17 00:00:00 2001 From: designhorf Date: Mon, 26 Aug 2019 12:34:30 +0200 Subject: [PATCH 025/207] feat: added Select Network and hide it --- src/renderer/wallet/main/sidebar.jsx | 33 ++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/renderer/wallet/main/sidebar.jsx b/src/renderer/wallet/main/sidebar.jsx index 69636b121..78b86c0dd 100644 --- a/src/renderer/wallet/main/sidebar.jsx +++ b/src/renderer/wallet/main/sidebar.jsx @@ -7,6 +7,9 @@ import { ListItemIcon, Grid, Typography, + // Input, + // MenuItem, + // Select, Divider } from '@material-ui/core'; import { Link } from 'react-router-dom'; @@ -22,6 +25,7 @@ import { // MenuAffiliateIcon, // MenuExportIcon } from 'selfkey-ui'; +// import { KeyboardArrowDown } from '@material-ui/icons'; const styles = theme => ({ list: { @@ -147,6 +151,13 @@ const styles = theme => ({ }, listItemIcon: { marginRight: '22px' + }, + select: { + width: '160px' + }, + network: { + marginBottom: '30px', + paddingLeft: '20px' } }); @@ -287,6 +298,28 @@ class Sidebar extends Component {
+ {/* + + Network + + + */} Date: Mon, 26 Aug 2019 18:00:19 +0200 Subject: [PATCH 026/207] feat: added tooltip to Network --- src/renderer/wallet/main/sidebar.jsx | 45 +++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/src/renderer/wallet/main/sidebar.jsx b/src/renderer/wallet/main/sidebar.jsx index 78b86c0dd..62038b3fd 100644 --- a/src/renderer/wallet/main/sidebar.jsx +++ b/src/renderer/wallet/main/sidebar.jsx @@ -10,6 +10,7 @@ import { // Input, // MenuItem, // Select, + // IconButton Divider } from '@material-ui/core'; import { Link } from 'react-router-dom'; @@ -21,9 +22,13 @@ import { SelfkeyLogo, MenuHelpIcon, SwitchAccountsIcon, - PowerIcon + PowerIcon, + // KeyTooltip, + // TooltipArrow, // MenuAffiliateIcon, // MenuExportIcon + // InfoTooltip, + primary } from 'selfkey-ui'; // import { KeyboardArrowDown } from '@material-ui/icons'; @@ -158,6 +163,17 @@ const styles = theme => ({ network: { marginBottom: '30px', paddingLeft: '20px' + }, + tooltip: { + marginTop: '-2px', + padding: '0 0 0 10px' + }, + customWidth: { + maxWidth: '168px' + }, + tooltipLink: { + color: primary, + textDecoration: 'none' } }); @@ -301,6 +317,33 @@ class Sidebar extends Component { {/* Network + + + Modify the network settings to go from Ethereum Mainnet + to Ropsten testnet.{' '} + + What is a testnet? + + + + + } + > + + + + + {this + .state + .error !== + '' && ( + + { + this + .state + .error + } + + )} + + + + Legal + Entity + Name* + + + + + + +
+ + + + + Legal + Entity + Type* + + + + + + + + + + + + Creation + Date* + + + + + + + + + + + + Contact + Email + (optional) + + + + + {this + .state + .errorEmail && ( + + { + 'Email provided is invalid' + } + + )} + + + + + + + + Tax + ID + (optional) + + + + + {this + .state + .errorEmail && ( + + { + 'Email provided is invalid' + } + + )} + + + +
+
+
+
+
+ + + + + + + + + + + + + + +
+ + + + + + + + + + Name + + + + + Type + + + + + Role + + + + + Citizenship / + Incorporation + + + + + Residency / Domicile + + + + + Shares + + + + + Actions + + + + + + {members && + members.map(entry => { + return ( + + + + {entry.name} + + + + {entry.type} + + + {entry.role} + + + { + entry.citizenship + } + + + { + entry.residency + } + + + + { + entry.shares + } + + + + + { + this.handleEditMember( + entry + ); + }} + /> + + { + this.handleDeleteMember( + entry + ); + }} + > + + + + + ); + })} + +
+
+
+ + + + + +
+
+
+
+
+
+ + + + + + + + + + + + ); + } +} + +const mapStateToProps = (state, props) => { + return { + walletType: appSelectors.selectWalletType(state), + members: dummyMembers + }; +}; + +export const CreateCorporateProfile = connect(mapStateToProps)( + withStyles(styles)(CreateCorporateProfileComponent) +); + +export default CreateCorporateProfile; diff --git a/src/renderer/wallet/main/index.jsx b/src/renderer/wallet/main/index.jsx index 5930e2771..c0f2d2e51 100644 --- a/src/renderer/wallet/main/index.jsx +++ b/src/renderer/wallet/main/index.jsx @@ -1,5 +1,6 @@ import React, { Component } from 'react'; import { Route } from 'react-router-dom'; +import { push } from 'connected-react-router'; import Dashboard from '../../dashboard'; import { CryptoMangerContainer, AddTokenContainer } from '../../crypto-manager'; import AddressBook from '../../address-book/main'; @@ -49,6 +50,7 @@ import ReactPiwik from 'react-piwik'; import CreateDID from '../../selfkey-id/main/components/create-did'; import CreateDIDProcessing from '../../selfkey-id/main/components/create-did-processing'; import HardwareWalletTransactionTimer from '../../transaction/send/timer'; +import CreateCorporateProfile from '../../selfkey-id/main/components/create-corporate-profile'; const styles = theme => ({ headerSection: { @@ -86,6 +88,11 @@ class Main extends Component { this.setMatomoId(); } + createProfile = evt => { + evt && evt.preventDefault(); + this.props.dispatch(push('/main/create-corporate-profile')); + }; + render() { const { match, classes } = this.props; return ( @@ -97,7 +104,7 @@ class Main extends Component { className={classes.page} > - + @@ -217,6 +224,10 @@ class Main extends Component { path={`${match.path}/create-did-processing`} component={CreateDIDProcessing} /> + ); diff --git a/src/renderer/wallet/main/toolbar.jsx b/src/renderer/wallet/main/toolbar.jsx index faef44c6f..13602cf4f 100644 --- a/src/renderer/wallet/main/toolbar.jsx +++ b/src/renderer/wallet/main/toolbar.jsx @@ -1,14 +1,6 @@ import React, { Component } from 'react'; -import { - withStyles, - Grid - // Typography -} from '@material-ui/core'; -import { - MenuNewIcon - // DropdownIcon, - // PersonIcon -} from 'selfkey-ui'; +import { createStyles, withStyles, Button, Grid, Typography } from '@material-ui/core'; +import { MenuNewIcon, DropdownIcon, PersonIcon, CorporateIcon } from 'selfkey-ui'; import PriceBox from '../../price-box'; import Sidebar from './sidebar'; import config from 'common/config'; @@ -67,12 +59,111 @@ const styles = theme => ({ height: '59px', marginTop: '16px', width: '1px' + }, + profileContainer: { + width: '100%', + position: 'absolute', + zIndex: '999' + }, + openedProfile: { + transform: 'scaleY(-1)', + '-webkit-transform': 'scaleY(-1)' + }, + closedProfile: { + transform: 'scaleY(1)', + '-webkit-transform': 'scaleY(1)' } }); +const profileStyle = theme => + createStyles({ + profile: { + minWidth: '201px', + maxWidth: '201px', + float: 'right', + padding: '20px 20px 8px 20px', + borderRadius: '4px', + backgroundColor: '#262f39', + border: 'solid 1px #303c49' + }, + profileFooter: { + bottom: '7px', + marginTop: '10px' + }, + horizontalDivider: { + height: '1px', + backgroundColor: '#303c49' + }, + profileBox: { + padding: '20px 0px 14px 6px', + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'center' + }, + profileDetail: { + paddingBottom: '20px' + }, + profileName: { + paddingLeft: '28px' + } + }); + +const Profile = withStyles(profileStyle)(({ classes, profiles, isOpen, onClick }) => { + return ( + isOpen && ( +
+ {profiles && + profiles.map((el, index) => ( + + + {el.profileType === 'company' ? : } + + + {`${el.firstName} ${ + el.lastName + }`} + + {`${el.profileType.charAt(0).toUpperCase() + + el.profileType.slice(1)} Profile`} + + + + ))} + +
+ + + + + + +
+ ) + ); +}); + +const dummyProfiles = [ + { + id: '1', + firstName: 'Acme', + lastName: 'Corp', + profileType: 'company' + }, + { + id: '2', + firstName: 'Standard United', + lastName: 'Bank', + profileType: 'company' + } +]; + class Toolbar extends Component { state = { - isSidebarOpen: true + isSidebarOpen: true, + isProfileOpen: false }; toggleDrawer = isSidebarOpen => { @@ -81,72 +172,102 @@ class Toolbar extends Component { }); }; + toggleProfile = isProfileOpen => { + this.setState({ + isProfileOpen + }); + }; + + createProfile = evt => { + this.toggleProfile(!this.state.isProfileOpen); + return this.props.createProfile(evt); + }; + render() { const { classes } = this.props; return ( -
- - this.toggleDrawer(!this.state.isSidebarOpen)} - /> - - - - - - - - + +
+ + this.toggleDrawer(!this.state.isSidebarOpen)} + /> + + + + + + + + + - - {/* PROFILE SWITCH - DROPDOWN - - - -
- - - - - - - - - Name - - Personal Profile - - - - + + + +
+ + + + + + + + + Name Surname + + Personal Profile + + + + + this.toggleProfile( + !this.state.isProfileOpen + ) + } + /> + - */} - -
+
+
+
+ +
+ ); } } From da24381bebfe0bd0e6547356b8f8c6f8bf7012d0 Mon Sep 17 00:00:00 2001 From: designhorf Date: Tue, 3 Sep 2019 11:00:51 +0200 Subject: [PATCH 061/207] fix: changed bg color of dropdown in toolbar --- src/renderer/wallet/main/toolbar.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/wallet/main/toolbar.jsx b/src/renderer/wallet/main/toolbar.jsx index 13602cf4f..60c079e0c 100644 --- a/src/renderer/wallet/main/toolbar.jsx +++ b/src/renderer/wallet/main/toolbar.jsx @@ -83,7 +83,7 @@ const profileStyle = theme => float: 'right', padding: '20px 20px 8px 20px', borderRadius: '4px', - backgroundColor: '#262f39', + backgroundColor: '#1E262E', border: 'solid 1px #303c49' }, profileFooter: { From 439e56d17555d5f17f51fda2e0bd1ef2f9b64be9 Mon Sep 17 00:00:00 2001 From: designhorf Date: Tue, 3 Sep 2019 11:02:25 +0200 Subject: [PATCH 062/207] feat: added new icons to dropdown in toolbar --- src/renderer/wallet/main/toolbar.jsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/renderer/wallet/main/toolbar.jsx b/src/renderer/wallet/main/toolbar.jsx index 60c079e0c..23697f51f 100644 --- a/src/renderer/wallet/main/toolbar.jsx +++ b/src/renderer/wallet/main/toolbar.jsx @@ -1,6 +1,6 @@ import React, { Component } from 'react'; import { createStyles, withStyles, Button, Grid, Typography } from '@material-ui/core'; -import { MenuNewIcon, DropdownIcon, PersonIcon, CorporateIcon } from 'selfkey-ui'; +import { MenuNewIcon, DropdownIcon, RoundCompany, RoundPerson } from 'selfkey-ui'; import PriceBox from '../../price-box'; import Sidebar from './sidebar'; import config from 'common/config'; @@ -117,7 +117,7 @@ const Profile = withStyles(profileStyle)(({ classes, profiles, isOpen, onClick } profiles.map((el, index) => ( - {el.profileType === 'company' ? : } + {el.profileType === 'company' ? : } {`${el.firstName} ${ @@ -228,7 +228,7 @@ class Toolbar extends Component { - + Name Surname From f18a43d7d95899a8af32944614484d3971848e9a Mon Sep 17 00:00:00 2001 From: Eduardo Santiago Moura Date: Tue, 3 Sep 2019 08:37:43 -0300 Subject: [PATCH 063/207] feat(corp1): ui add create entity button to menu --- src/renderer/wallet/main/index.jsx | 12 ++- src/renderer/wallet/main/toolbar.jsx | 106 ++++++++++++++++++--------- 2 files changed, 80 insertions(+), 38 deletions(-) diff --git a/src/renderer/wallet/main/index.jsx b/src/renderer/wallet/main/index.jsx index c0f2d2e51..d45bdbbb2 100644 --- a/src/renderer/wallet/main/index.jsx +++ b/src/renderer/wallet/main/index.jsx @@ -88,7 +88,12 @@ class Main extends Component { this.setMatomoId(); } - createProfile = evt => { + createPersonalProfile = evt => { + evt && evt.preventDefault(); + this.props.dispatch(push('/selfKeyIdCreate')); + }; + + createCorporateProfile = evt => { evt && evt.preventDefault(); this.props.dispatch(push('/main/create-corporate-profile')); }; @@ -104,7 +109,10 @@ class Main extends Component { className={classes.page} > - + diff --git a/src/renderer/wallet/main/toolbar.jsx b/src/renderer/wallet/main/toolbar.jsx index 13602cf4f..a2c43f490 100644 --- a/src/renderer/wallet/main/toolbar.jsx +++ b/src/renderer/wallet/main/toolbar.jsx @@ -94,7 +94,14 @@ const profileStyle = theme => height: '1px', backgroundColor: '#303c49' }, - profileBox: { + profilePersonal: { + padding: '20px 0px 4px 6px', + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'center' + }, + profileCorporate: { padding: '20px 0px 14px 6px', display: 'flex', flexDirection: 'row', @@ -106,44 +113,65 @@ const profileStyle = theme => }, profileName: { paddingLeft: '28px' + }, + button: { + width: '189px' } }); -const Profile = withStyles(profileStyle)(({ classes, profiles, isOpen, onClick }) => { - return ( - isOpen && ( -
- {profiles && - profiles.map((el, index) => ( - - - {el.profileType === 'company' ? : } - - - {`${el.firstName} ${ - el.lastName - }`} - - {`${el.profileType.charAt(0).toUpperCase() + - el.profileType.slice(1)} Profile`} - +const Profile = withStyles(profileStyle)( + ({ classes, profiles, isOpen, onClickPersonal, onClickCorporate }) => { + return ( + isOpen && ( +
+ {profiles && + profiles.map((el, index) => ( + + + {el.profileType === 'company' ? ( + + ) : ( + + )} + + + {`${el.firstName} ${ + el.lastName + }`} + + {`${el.profileType.charAt(0).toUpperCase() + + el.profileType.slice(1)} Profile`} + + + ))} + +
+ + + + - ))} - -
- - - - - -
- ) - ); -}); + + + + + +
+ ) + ); + } +); const dummyProfiles = [ { @@ -178,9 +206,14 @@ class Toolbar extends Component { }); }; - createProfile = evt => { + createPersonalProfile = evt => { + this.toggleProfile(!this.state.isProfileOpen); + return this.props.createPersonalProfile(evt); + }; + + createCorporateProfile = evt => { this.toggleProfile(!this.state.isProfileOpen); - return this.props.createProfile(evt); + return this.props.createCorporateProfile(evt); }; render() { @@ -264,7 +297,8 @@ class Toolbar extends Component {
From e38cb9847876b453d195010e90de65258d23ebef Mon Sep 17 00:00:00 2001 From: designhorf Date: Tue, 3 Sep 2019 16:44:07 +0200 Subject: [PATCH 064/207] fix: alignment of form --- .../components/create-corporate-profile.jsx | 157 +++++++++++------- 1 file changed, 94 insertions(+), 63 deletions(-) diff --git a/src/renderer/selfkey-id/main/components/create-corporate-profile.jsx b/src/renderer/selfkey-id/main/components/create-corporate-profile.jsx index dc6199c58..084db0202 100644 --- a/src/renderer/selfkey-id/main/components/create-corporate-profile.jsx +++ b/src/renderer/selfkey-id/main/components/create-corporate-profile.jsx @@ -68,9 +68,6 @@ const styles = theme => ({ marginTop: '10px', marginBottom: '10px' }, - input: { - width: '322px' - }, dropdown: { width: '322px' }, @@ -78,6 +75,16 @@ const styles = theme => ({ alignItems: 'baseline', display: 'flex', flexDirection: 'row' + }, + inputStop: { + marginBottom: '35px', + width: '47%' + }, + optional: { + display: 'inline', + fontStyle: 'italic', + marginLeft: '5px', + textTransform: 'lowercase' } }); @@ -175,17 +182,31 @@ class CreateCorporateProfileComponent extends Component { direction="column" justify="center" alignItems="center" - spacing={32} + spacing={0} + xs={12} > - + - + - + - + )} + + - + - + - + - - - + - + Contact Email - (optional) + + (optional) + - + - - Tax ID - (optional) + + (optional) + - + Date: Tue, 3 Sep 2019 16:57:34 +0200 Subject: [PATCH 065/207] feat: updated Selfkey UI --- package.json | 2 +- yarn.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 8954d3067..96ae8d3bd 100644 --- a/package.json +++ b/package.json @@ -113,7 +113,7 @@ "reselect": "4.0.0", "sanitize-html": "1.20.0", "scrypt": "6.0.3", - "selfkey-ui": "https://github.com/SelfKeyFoundation/selfkey-ui.git#016e13f5f602a12cef15bdb86464ef5b876a902a", + "selfkey-ui": "https://github.com/SelfKeyFoundation/selfkey-ui.git#8ee46e4c6cfb995900648cb5050448a26ec928b5", "selfkey.js": "1.0.24", "serialize-error": "3.0.0", "snyk": "1.216.0", diff --git a/yarn.lock b/yarn.lock index 37c291f74..59e046a25 100644 --- a/yarn.lock +++ b/yarn.lock @@ -18979,9 +18979,9 @@ select@^1.1.2: resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d" integrity sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0= -"selfkey-ui@https://github.com/SelfKeyFoundation/selfkey-ui.git#016e13f5f602a12cef15bdb86464ef5b876a902a": +"selfkey-ui@https://github.com/SelfKeyFoundation/selfkey-ui.git#8ee46e4c6cfb995900648cb5050448a26ec928b5": version "1.0.0" - resolved "https://github.com/SelfKeyFoundation/selfkey-ui.git#016e13f5f602a12cef15bdb86464ef5b876a902a" + resolved "https://github.com/SelfKeyFoundation/selfkey-ui.git#8ee46e4c6cfb995900648cb5050448a26ec928b5" dependencies: "@material-ui/core" "3.9.2" "@material-ui/icons" "3.0.2" From 66a3051fe7ed5e90d4e11aee9fc2880612b4296b Mon Sep 17 00:00:00 2001 From: designhorf Date: Wed, 4 Sep 2019 09:38:54 +0200 Subject: [PATCH 066/207] fix: size of Picker and added dropdowns --- .../components/create-corporate-profile.jsx | 179 ++++++++++++------ 1 file changed, 126 insertions(+), 53 deletions(-) diff --git a/src/renderer/selfkey-id/main/components/create-corporate-profile.jsx b/src/renderer/selfkey-id/main/components/create-corporate-profile.jsx index 084db0202..3b4caca10 100644 --- a/src/renderer/selfkey-id/main/components/create-corporate-profile.jsx +++ b/src/renderer/selfkey-id/main/components/create-corporate-profile.jsx @@ -16,9 +16,12 @@ import { Typography, Button, Input, + MenuItem, + Select, withStyles } from '@material-ui/core'; -import { EditTransparentIcon, DeleteIcon, SmallTableHeadRow } from 'selfkey-ui'; +import { KeyboardArrowDown } from '@material-ui/icons'; +import { EditTransparentIcon, DeleteIcon, SmallTableHeadRow, KeyPicker } from 'selfkey-ui'; import backgroundImage from '../../../../../static/assets/images/icons/icon-marketplace.png'; @@ -76,10 +79,18 @@ const styles = theme => ({ display: 'flex', flexDirection: 'row' }, - inputStop: { + inputBox: { marginBottom: '35px', width: '47%' }, + keyBox: { + marginBottom: '35px', + marginRight: 'calc(47% - 200px)', + width: '200px', + '& .rdt': { + width: '180px' + } + }, optional: { display: 'inline', fontStyle: 'italic', @@ -225,7 +236,7 @@ class CreateCorporateProfileComponent extends Component { container direction="column" className={ - classes.inputStop + classes.inputBox } > @@ -237,48 +248,65 @@ class CreateCorporateProfileComponent extends Component { } > Legal - Jurisdiction* + Jurisdiction - } - placeholder="Legal Jurisdiction" - /> - {this - .state - .error !== - '' && ( - - { - this - .state - .error - } - - )} + style={{ + width: + '100%' + }} + > + + + Choose... + + + {[ + 'Jurisdiction 1', + 'Jurisdiction 2', + 'Jurisdiction 3', + 'Jurisdiction 4', + 'Jurisdiction 5' + ].map( + item => ( + + { + item + } + + ) + )} + @@ -288,7 +316,7 @@ class CreateCorporateProfileComponent extends Component { > Legal Entity - Name* + Name @@ -316,7 +344,7 @@ class CreateCorporateProfileComponent extends Component { container direction="column" className={ - classes.inputStop + classes.inputBox } > @@ -326,27 +354,64 @@ class CreateCorporateProfileComponent extends Component { > Legal Entity - Type* + Type - + input={ + + } + style={{ + width: + '100%' + }} + > + + + Choose... + + + {[ + 'Entity Type 1', + 'Entity Type 2', + 'Entity Type 3', + 'Entity Type 4', + 'Entity Type 5' + ].map( + item => ( + + { + item + } + + ) + )} + @@ -355,18 +420,26 @@ class CreateCorporateProfileComponent extends Component { gutterBottom > Creation - Date* + Date - div': { + width: + '200px !important' + } + }} /> @@ -382,7 +455,7 @@ class CreateCorporateProfileComponent extends Component { container direction="column" className={ - classes.inputStop + classes.inputBox } > @@ -438,7 +511,7 @@ class CreateCorporateProfileComponent extends Component { container direction="column" className={ - classes.inputStop + classes.inputBox } > From 13d892be592225dddf1020b956aeab5f3283f8a2 Mon Sep 17 00:00:00 2001 From: designhorf Date: Wed, 4 Sep 2019 14:29:25 +0200 Subject: [PATCH 067/207] fix: removed border bottom from Sidebar --- src/renderer/wallet/main/sidebar.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/renderer/wallet/main/sidebar.jsx b/src/renderer/wallet/main/sidebar.jsx index 3fa3624b3..ed2ed41db 100644 --- a/src/renderer/wallet/main/sidebar.jsx +++ b/src/renderer/wallet/main/sidebar.jsx @@ -115,6 +115,7 @@ const styles = theme => ({ drawer: { transition: 'all 3s', '& > div:first-of-type': { + borderBottom: 'none', left: 0, opacity: '1 !important', right: 'auto' From 21afed63eee86b2095b1159b9c382320aeb4b9b1 Mon Sep 17 00:00:00 2001 From: designhorf Date: Wed, 4 Sep 2019 14:49:39 +0200 Subject: [PATCH 068/207] fix: removed horizontal scroll from Sidebar --- src/renderer/wallet/main/sidebar.jsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/renderer/wallet/main/sidebar.jsx b/src/renderer/wallet/main/sidebar.jsx index ed2ed41db..a20ba9332 100644 --- a/src/renderer/wallet/main/sidebar.jsx +++ b/src/renderer/wallet/main/sidebar.jsx @@ -127,6 +127,7 @@ const styles = theme => ({ transition: 'all 0.2s ease-out' }, '& .sidebarContainer': { + overflow: 'auto', transition: 'all 0.2s ease-out', width: 200 }, @@ -144,6 +145,7 @@ const styles = theme => ({ transition: 'all 0.2s ease-out' }, '& .sidebarContainer': { + overflow: 'hidden', transition: 'all 0.2s ease-out', width: 56 }, From 20670bb4378ed89c5158a3b7d684955031e4b8e8 Mon Sep 17 00:00:00 2001 From: designhorf Date: Wed, 4 Sep 2019 15:14:49 +0200 Subject: [PATCH 069/207] fix: add link to entire logo --- src/renderer/wallet/main/sidebar.jsx | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/renderer/wallet/main/sidebar.jsx b/src/renderer/wallet/main/sidebar.jsx index a20ba9332..131a73e78 100644 --- a/src/renderer/wallet/main/sidebar.jsx +++ b/src/renderer/wallet/main/sidebar.jsx @@ -63,7 +63,10 @@ const styles = theme => ({ cursor: 'pointer' }, link: { + alignItems: 'center', + display: 'flex', outline: 'none', + textDecoration: 'none', '&:focus': { outline: 'none' } @@ -220,7 +223,7 @@ class Sidebar extends Component { className={`${classes.list} sidebarContainer`} spacing={40} > - + + + SELFKEY + - - SELFKEY - From 0ca9530eae8c33d70a9dc3b4eea400e2b81ea379 Mon Sep 17 00:00:00 2001 From: designhorf Date: Wed, 4 Sep 2019 15:23:13 +0200 Subject: [PATCH 070/207] fix: set closed as default state of Sidebar --- src/renderer/wallet/main/toolbar.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/wallet/main/toolbar.jsx b/src/renderer/wallet/main/toolbar.jsx index faef44c6f..50b8e69ef 100644 --- a/src/renderer/wallet/main/toolbar.jsx +++ b/src/renderer/wallet/main/toolbar.jsx @@ -72,7 +72,7 @@ const styles = theme => ({ class Toolbar extends Component { state = { - isSidebarOpen: true + isSidebarOpen: false }; toggleDrawer = isSidebarOpen => { From 55c404a09e024cc23569e68da84935ffb09263fa Mon Sep 17 00:00:00 2001 From: designhorf Date: Wed, 4 Sep 2019 15:56:39 +0200 Subject: [PATCH 071/207] fix: width of category header --- src/renderer/marketplace/categories/category.jsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/renderer/marketplace/categories/category.jsx b/src/renderer/marketplace/categories/category.jsx index f6821e8b2..533bf3c02 100644 --- a/src/renderer/marketplace/categories/category.jsx +++ b/src/renderer/marketplace/categories/category.jsx @@ -24,8 +24,9 @@ const styles = theme => ({ header: { backgroundColor: '#2a3540', + borderRadius: '3px 3px 0 0', height: '76px', - width: '340px' + width: '338px' }, svgIcon: { @@ -58,7 +59,7 @@ const styles = theme => ({ }, header: { - width: '360px' + width: '358px' } } }); From 5c6f4f25df65fbc56e36a8492511f0f28cf0d6d0 Mon Sep 17 00:00:00 2001 From: designhorf Date: Thu, 5 Sep 2019 11:11:01 +0200 Subject: [PATCH 072/207] feat: updated Selfkey UI --- package.json | 2 +- yarn.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 8954d3067..cb1535b54 100644 --- a/package.json +++ b/package.json @@ -113,7 +113,7 @@ "reselect": "4.0.0", "sanitize-html": "1.20.0", "scrypt": "6.0.3", - "selfkey-ui": "https://github.com/SelfKeyFoundation/selfkey-ui.git#016e13f5f602a12cef15bdb86464ef5b876a902a", + "selfkey-ui": "https://github.com/SelfKeyFoundation/selfkey-ui.git#27a24b4d3f190ef52fd393a62e8df920d48baf4e", "selfkey.js": "1.0.24", "serialize-error": "3.0.0", "snyk": "1.216.0", diff --git a/yarn.lock b/yarn.lock index 37c291f74..27e3a08eb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -18979,9 +18979,9 @@ select@^1.1.2: resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d" integrity sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0= -"selfkey-ui@https://github.com/SelfKeyFoundation/selfkey-ui.git#016e13f5f602a12cef15bdb86464ef5b876a902a": +"selfkey-ui@https://github.com/SelfKeyFoundation/selfkey-ui.git#27a24b4d3f190ef52fd393a62e8df920d48baf4e": version "1.0.0" - resolved "https://github.com/SelfKeyFoundation/selfkey-ui.git#016e13f5f602a12cef15bdb86464ef5b876a902a" + resolved "https://github.com/SelfKeyFoundation/selfkey-ui.git#27a24b4d3f190ef52fd393a62e8df920d48baf4e" dependencies: "@material-ui/core" "3.9.2" "@material-ui/icons" "3.0.2" From d56b84298c96e0c7187b39f02970a689563732b8 Mon Sep 17 00:00:00 2001 From: Maxim Kovalov Date: Thu, 5 Sep 2019 13:08:06 +0300 Subject: [PATCH 073/207] feat(identity): integrate identity model WIP --- src/common/identity/identity-duck.spec.js | 6 ++--- src/common/identity/operations.js | 17 +++++++------- src/common/identity/selectors.js | 23 +++++++++++++++---- .../components/selfkey-id-create-form.jsx | 2 +- 4 files changed, 30 insertions(+), 18 deletions(-) diff --git a/src/common/identity/identity-duck.spec.js b/src/common/identity/identity-duck.spec.js index e26b0f3ff..6d1fe7d86 100644 --- a/src/common/identity/identity-duck.spec.js +++ b/src/common/identity/identity-duck.spec.js @@ -58,7 +58,7 @@ describe('Identity Duck', () => { expect( identityActions.deleteDocumentsAction.calledOnceWith(testWalletId) ).toBeTruthy(); - expect(store.dispatch.callCount).toBe(2); + expect(store.dispatch.callCount).toBe(3); }); it('unlockIdentityOperation', async () => { sinon.stub(identityOperations, 'loadIdAttributesOperation').returns(() => {}); @@ -648,9 +648,7 @@ describe('Identity Duck', () => { store.getState.bind(store) ); - expect( - identityService.createIdAttribute.calledOnceWith(testAttribute) - ).toBeTruthy(); + expect(identityService.createIdAttribute.getCall(0).args).toEqual(testAttribute); expect( testExports.operations.loadDocumentsForAttributeOperation.calledOnceWith(1) ).toBeTruthy(); diff --git a/src/common/identity/operations.js b/src/common/identity/operations.js index 69fd99936..6d9d2e1f8 100644 --- a/src/common/identity/operations.js +++ b/src/common/identity/operations.js @@ -1,4 +1,4 @@ -import { walletSelectors, walletOperations } from '../wallet'; +import { walletOperations } from '../wallet'; import { getGlobalContext } from '../context'; import { createAliasedAction } from 'electron-redux'; import { push } from 'connected-react-router'; @@ -78,10 +78,9 @@ const removeDocumentOperation = documentId => async (dispatch, getState) => { const createIdAttributeOperation = attribute => async (dispatch, getState) => { let identityService = getGlobalContext().identityService; - // TODO: XXX fix wallet selector - const wallet = walletSelectors.getWallet(getState()); - const walletId = attribute.walletId || wallet.id; - attribute = { ...attribute, walletId }; + const identity = identitySelectors.selectCurrentIdentity(getState()); + const identityId = attribute.identityId || identity.id; + attribute = { ...attribute, identityId }; attribute = await identityService.createIdAttribute(attribute); await dispatch(operations.loadDocumentsForAttributeOperation(attribute.id)); await dispatch(identityActions.addIdAttributeAction(attribute)); @@ -102,6 +101,7 @@ const editIdAttributeOperation = attribute => async (dispatch, getState) => { }; const updateProfilePictureOperation = (picture, identityId) => (dispatch, getState) => { + // TODO max: move avatar handling to identity module return dispatch(walletOperations.updateWalletAvatar(picture, identityId)); }; @@ -116,13 +116,14 @@ const unlockIdentityOperation = identityId => async (dispatch, getState) => { await dispatch(identityOperations.setCurrentIdentityAction(identityId)); }; -const createSelfkeyIdOperation = (walletId, data) => async (dispatch, getState) => { +const createSelfkeyIdOperation = (identityId, data) => async (dispatch, getState) => { const idAttributeTypes = identitySelectors.selectIdAttributeTypes(getState()); + const identity = identitySelectors.selectIdentityById(getState(), identityId); const getTypeId = url => { return idAttributeTypes.find(idAttributeType => idAttributeType.url === url).id; }; // TODO: XXX update to entity operations - await dispatch(walletOperations.updateWalletName(data.nickName, walletId)); + await dispatch(walletOperations.updateWalletName(data.nickName, identity.walletId)); await dispatch( identityOperations.createIdAttributeOperation({ @@ -148,7 +149,7 @@ const createSelfkeyIdOperation = (walletId, data) => async (dispatch, getState) }) ); - await dispatch(walletOperations.updateWalletSetup(true, walletId)); + await dispatch(identityOperations.updateIdentitySetup(true, identityId)); await dispatch(push('/selfkeyIdCreateAbout')); }; diff --git a/src/common/identity/selectors.js b/src/common/identity/selectors.js index f5a1320a8..c47645d99 100644 --- a/src/common/identity/selectors.js +++ b/src/common/identity/selectors.js @@ -1,6 +1,6 @@ -import { walletSelectors } from '../wallet'; import { jsonSchema, identityAttributes } from './utils'; import { forceUpdateAttributes } from 'common/config'; +import { walletSelectors } from 'common/wallet'; const EMAIL_ATTRIBUTE = 'http://platform.selfkey.org/schema/attribute/email.json'; const FIRST_NAME_ATTRIBUTE = 'http://platform.selfkey.org/schema/attribute/first-name.json'; @@ -132,9 +132,9 @@ const selectFullIdAttributesByIds = (state, identityId, attributeIds = null) => }; const selectSelfkeyId = state => { + const identity = identitySelectors.selectCurrentIdentity(state); const wallet = walletSelectors.getWallet(state); - // TODO: XXX switch wallet to identity - const allAttributes = identitySelectors.selectFullIdAttributesByIds(state, wallet.id); + const allAttributes = identitySelectors.selectFullIdAttributesByIds(state, identity.id); // FIXME: all base attribute types should be rendered (even if not created yet) const basicAttributes = allAttributes.reduce( @@ -160,8 +160,9 @@ const selectSelfkeyId = state => { if (!attr || !attr.data || !attr.data.value) return ''; return attr.data.value; }; - + // TODO max: move profile picture to identity model return { + identity, wallet, profilePicture: wallet.profilePicture, allAttributes, @@ -175,6 +176,16 @@ const selectSelfkeyId = state => { }; }; +const selectIdentityById = (state, id) => { + const tree = selectIdentity(state); + return tree.identitiesById[id]; +}; + +const selectCurrentIdentity = state => { + const tree = selectIdentity(state); + return tree.identitiesById[tree.currentIdentity]; +}; + export const identitySelectors = { selectIdentity, selectCountries, @@ -190,7 +201,9 @@ export const identitySelectors = { selectDocumentsByAttributeIds, selectFullIdAttributesByIds, selectSelfkeyId, - selectUiSchema + selectUiSchema, + selectCurrentIdentity, + selectIdentityById }; export default identitySelectors; diff --git a/src/renderer/selfkey-id/main/components/selfkey-id-create-form.jsx b/src/renderer/selfkey-id/main/components/selfkey-id-create-form.jsx index be23a32f8..5ec265c12 100644 --- a/src/renderer/selfkey-id/main/components/selfkey-id-create-form.jsx +++ b/src/renderer/selfkey-id/main/components/selfkey-id-create-form.jsx @@ -117,7 +117,7 @@ class SelfKeyIdCreateFormComponent extends Component { handleSave = evt => { evt.preventDefault(); this.props.dispatch( - identityOperations.createSelfkeyIdOperation(this.props.wallet.id, { ...this.state }) + identityOperations.createSelfkeyIdOperation(this.props.identity.id, { ...this.state }) ); }; From 7f97c304cd401fb2004a856f7ddbb6e44c460804 Mon Sep 17 00:00:00 2001 From: designhorf Date: Thu, 5 Sep 2019 12:19:54 +0200 Subject: [PATCH 074/207] feat: fixed position of toolbar --- src/renderer/wallet/main/index.jsx | 2 +- src/renderer/wallet/main/toolbar.jsx | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/renderer/wallet/main/index.jsx b/src/renderer/wallet/main/index.jsx index b8f54204e..5e14b865c 100644 --- a/src/renderer/wallet/main/index.jsx +++ b/src/renderer/wallet/main/index.jsx @@ -71,7 +71,7 @@ const styles = theme => ({ const contentWrapperStyle = { marginBottom: '60px', marginRight: '-55px', - marginTop: '50px' + marginTop: '128px' }; class Main extends Component { diff --git a/src/renderer/wallet/main/toolbar.jsx b/src/renderer/wallet/main/toolbar.jsx index 50b8e69ef..ae4982cc1 100644 --- a/src/renderer/wallet/main/toolbar.jsx +++ b/src/renderer/wallet/main/toolbar.jsx @@ -17,7 +17,10 @@ const styles = theme => ({ wrapper: { backgroundColor: '#27333D', boxShadow: - 'inset 0 -1px 0 0 #475768, 1px 0 0 0 rgba(118,128,147,0.2), 2px 0 2px 0 rgba(0,0,0,0.2)' + 'inset 0 -1px 0 0 #475768, 1px 0 0 0 rgba(118,128,147,0.2), 2px 0 2px 0 rgba(0,0,0,0.2)', + padding: '0 2%', + position: 'fixed', + zIndex: 1 }, logo: { width: '38px', @@ -86,13 +89,6 @@ class Toolbar extends Component { return (
- this.toggleDrawer(!this.state.isSidebarOpen)} - /> + this.toggleDrawer(!this.state.isSidebarOpen)} + /> From 86021605ab1ec5553e52517b25fc1e06cec0dfac Mon Sep 17 00:00:00 2001 From: Andre Goncalves Date: Thu, 5 Sep 2019 11:20:03 +0100 Subject: [PATCH 075/207] feat: background map processing --- .../tax-treaties/tax-treaties-service.js | 29 ++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/src/main/marketplace/tax-treaties/tax-treaties-service.js b/src/main/marketplace/tax-treaties/tax-treaties-service.js index d4d051a9d..7d962ecc6 100644 --- a/src/main/marketplace/tax-treaties/tax-treaties-service.js +++ b/src/main/marketplace/tax-treaties/tax-treaties-service.js @@ -13,6 +13,17 @@ export const TAX_TREATIES_API_ENDPOINT = `${config.airtableBaseUrl}TaxTreaties${ isDevMode() ? 'Dev' : '' }`; +// Helper function to evenly distribute in time expensive background processing. +// This avoids blocking the event loop, and should be used when we are expecting +// to parse and process a very large number of (non time-critical) items +const executeAsync = (idx, fx) => + new Promise((resolve, reject) => + setTimeout(() => { + const item = fx(); + resolve(item); + }, idx * 10) + ); + export class TaxTreatiesService { constructor({ schedulerService }) { this.schedulerService = schedulerService; @@ -47,9 +58,14 @@ export class TaxTreatiesService { async fetchTaxTreatiesSelfkey() { try { let fetched = await request.get({ url: TAX_TREATIES_API_ENDPOINT, json: true }); - return fetched.entities.map(entity => - _.mapKeys(entity.data, (value, key) => _.camelCase(key)) + const data = await Promise.all( + fetched.entities.map((entity, idx) => + executeAsync(idx, () => + _.mapKeys(entity.data, (value, key) => _.camelCase(key)) + ) + ) ); + return data; } catch (error) { log.error(`fetchTaxTreatiesSelfkey: ${error}`); return []; @@ -58,9 +74,14 @@ export class TaxTreatiesService { async fetchTaxTreatiesFlagtheory() { try { let fetched = await request.get({ url: FLAGTHEORY_TAX_TREATIES_ENDPOINT, json: true }); - return fetched[0].map(entity => - _.mapKeys(_.omit(entity, 'id'), (value, key) => _.camelCase(key)) + const data = await Promise.all( + fetched[0].map((entity, idx) => + executeAsync(idx, () => + _.mapKeys(_.omit(entity, 'id'), (value, key) => _.camelCase(key)) + ) + ) ); + return data; } catch (error) { log.error(`fetchTaxTreatiesFlagtheory: ${error}`); return []; From 8170fb1492583ebeb5ea5f5cd00a6419dd19ecc9 Mon Sep 17 00:00:00 2001 From: designhorf Date: Thu, 5 Sep 2019 12:26:44 +0200 Subject: [PATCH 076/207] fix: alignment of marketplace category list --- src/renderer/marketplace/categories/categories-list.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/renderer/marketplace/categories/categories-list.jsx b/src/renderer/marketplace/categories/categories-list.jsx index a3b80fd0b..dfcc336a9 100644 --- a/src/renderer/marketplace/categories/categories-list.jsx +++ b/src/renderer/marketplace/categories/categories-list.jsx @@ -13,7 +13,8 @@ const styles = theme => ({ marginLeft: 0 }, width: '100%', - height: '120px' + height: '40px', + marginBottom: '20px' }, headerIcon: { marginLeft: '30px' From db549865ac4032fbc79873a529177320dd55c736 Mon Sep 17 00:00:00 2001 From: Maxim Kovalov Date: Thu, 5 Sep 2019 17:27:16 +0300 Subject: [PATCH 077/207] feat(identity): selfkey id refactor WIP --- src/main/blockchain/web3-service.js | 6 +- .../components/selfkey-id-applications.jsx | 277 ++---------------- .../main/components/selfkey-id-overview.jsx | 148 +++------- .../selfkey-id/main/components/selfkey-id.jsx | 41 +-- .../containers/selfkey-id-applications.js | 254 ++++++++++++++++ .../main/containers/selfkey-id-overview.js | 100 +++++++ .../selfkey-id/main/containers/selfkey-id.js | 61 +++- stories/selfkey-id.stories.js | 29 ++ 8 files changed, 515 insertions(+), 401 deletions(-) create mode 100644 src/renderer/selfkey-id/main/containers/selfkey-id-applications.js create mode 100644 src/renderer/selfkey-id/main/containers/selfkey-id-overview.js create mode 100644 stories/selfkey-id.stories.js diff --git a/src/main/blockchain/web3-service.js b/src/main/blockchain/web3-service.js index edb743de3..9eb890df0 100644 --- a/src/main/blockchain/web3-service.js +++ b/src/main/blockchain/web3-service.js @@ -99,7 +99,11 @@ export class Web3Service { setDefaultAccount(account) { this.web3.eth.accounts.wallet.add(account); - this.web3.eth.defaultAccount = account.address; + this.setDefaultAddress(account.address); + } + + setDefaultAddress(address) { + this.web3.eth.defaultAccount = address; } encryptAccount(account, password) { diff --git a/src/renderer/selfkey-id/main/components/selfkey-id-applications.jsx b/src/renderer/selfkey-id/main/components/selfkey-id-applications.jsx index 7787777b6..6acaef450 100644 --- a/src/renderer/selfkey-id/main/components/selfkey-id-applications.jsx +++ b/src/renderer/selfkey-id/main/components/selfkey-id-applications.jsx @@ -1,5 +1,5 @@ import React, { Component } from 'react'; -import config from 'common/config'; +import classNames from 'classnames'; import { Button, Card, @@ -35,14 +35,7 @@ import { error } from 'selfkey-ui'; import moment from 'moment'; -import classNames from 'classnames'; -import { push } from 'connected-react-router'; -import { connect } from 'react-redux'; -import { walletSelectors } from 'common/wallet'; -import { incorporationsOperations, incorporationsSelectors } from 'common/incorporations'; -import { kycSelectors, kycOperations, kycActions } from 'common/kyc'; import { Popup } from '../../../common/popup'; -import { appSelectors } from 'common/app'; const styles = theme => ({ statusIcon: { @@ -263,233 +256,20 @@ const HeaderIcon = withStyles(styles)(({ status, classes }) => { return icon; }); -const getRpInfo = (rpName, field) => { - return config.relyingPartyInfo[rpName][field]; -}; - -const getRpName = title => { - return title.toLowerCase().startsWith('bank account') ? 'Bank Accounts' : 'Incorporations'; -}; - -const MARKETPLACE_ROOT_PATH = '/main/marketplace-categories'; - class SelfkeyIdApplicationsComponent extends Component { - state = { - loading: false, - applicationId: null, - addingDocuments: false, - rpName: null, - refreshing: false, - showApplicationRefreshModal: false - }; - - async componentDidMount() { - const { rp, afterAuthRoute } = this.props; - const cancelRoute = `/main/selfkeyId`; - const authenticate = true; - - await this.props.dispatch(kycOperations.resetApplications()); - // if relying party not loaded, try again - if (!rp || !rp.authenticated) { - this.setState({ loading: true }, async () => { - await this.props.dispatch(kycOperations.setProcessing(true)); - await this.props.dispatch( - kycOperations.loadRelyingParty( - 'incorporations', - authenticate, - afterAuthRoute, - cancelRoute - ) - ); - }); - } - - // try to load existing kyc_applications data - await this.props.dispatch(kycOperations.loadApplicationsOperation()); - - // this is needed otherwise the rp keeps loading (stuck) - if (!this.props.incorporations || !this.props.incorporations.length) { - await this.props.dispatch(incorporationsOperations.loadIncorporationsOperation()); - } - } - - async componentDidUpdate(prevProps) { - if (prevProps.rp !== this.props.rp) { - if (this.props.rp.authenticated) { - await this.props.dispatch(kycOperations.loadApplicationsOperation()); - } - this.setState({ loading: false }, () => { - if (this.state.refreshing) { - if (this.state.applicationId) { - // try to refresh again after loading relying party - this.handleApplicationRefresh(this.state.applicationId); - } - } - if (this.state.addingDocuments) { - if (this.state.applicationId) { - // try to refresh again after loading relying party - this.handleApplicationAddDocuments( - this.state.applicationId, - this.state.rpName - ); - } - } - }); - } - } - - handleApplicationAddDocuments = (id, rpName) => { - const { rp, afterAuthRoute } = this.props; - const cancelRoute = `/main/selfkeyId`; - const authenticate = true; - - // if relying party not loaded, try again - if (!rp || !rp.authenticated) { - this.setState( - { loading: true, addingDocuments: true, applicationId: id, rpName }, - async () => { - await this.props.dispatch( - kycOperations.loadRelyingParty( - 'incorporations', - authenticate, - afterAuthRoute, - cancelRoute - ) - ); - } - ); - } else { - let self = this; - this.setState( - { - loading: false, - addingDocuments: false, - applicationId: null, - rpName: null - }, - async () => { - // Get current application info from kyc - let currentApplication = self.props.rp.applications.find(app => { - return app.id === id; - }); - // get stored application from local database - let application = this.props.applications.find(app => { - return app.id === id; - }); - const { - template, - vendor, - privacyPolicy, - termsOfService, - attributes - } = currentApplication; - const { rpName, title } = application; - /* eslint-disable camelcase */ - const description = application.sub_title; - /* eslint-enable camelcase */ - const agreement = true; - - // Set application data - await self.props.dispatch( - kycActions.setCurrentApplication( - rpName, - template, - afterAuthRoute, - cancelRoute, - title, - description, - agreement, - vendor, - privacyPolicy, - termsOfService, - attributes - ) - ); - - // Open add documents modal - // (Later on, we will need to improve this to be able to distinguish requirements - // that can be fulfilled by the wallet and ones that need redirect to KYCC.) - // - // await self.props.dispatch( - // kycOperations.loadRelyingParty( - // rpName, - // true, - // `/main/kyc/current-application/${rpName}?applicationId=${id}` - // ) - // ); - - // Redirects to KYCC chain on an external browser window with auto-login - const instanceUrl = self.props.rp.session.ctx.config.rootEndpoint; - const url = `${instanceUrl}/applications/${application.id}?access_token=${ - self.props.rp.session.access_token.jwt - }`; - window.openExternal(null, url); - } - ); - } - }; - - handleApplicationRefresh = id => { - const { afterAuthRoute } = this.props; - const cancelRoute = `/main/selfkeyId`; - const authenticate = true; - - // if relying party not loaded, try again - if (!this.state.refreshing) { - this.setState({ loading: true, refreshing: true, applicationId: id }, async () => { - await this.props.dispatch( - kycOperations.loadRelyingParty( - 'incorporations', - authenticate, - afterAuthRoute, - cancelRoute - ) - ); - }); - } else { - // get stored application from local database - let application = this.props.applications.find(app => { - return app.id === id; - }); - // get current application info from kyc - let kycApplication = this.props.rp.applications.find(app => { - return app.id === id; - }); - - if (application && kycApplication) { - // update stored application - application.currentStatus = kycApplication.currentStatus; - application.currentStatusName = kycApplication.statusName; - application.updatedAt = kycApplication.updatedAt; - } - - // sync of RP applications with local database is done automatically, all done, show modal - this.setState({ - refreshing: false, - applicationId: null, - showApplicationRefreshModal: true - }); - } - }; - renderLoadingScreen = () => ( ); - handleCloseApplicationRefreshModal = evt => { - evt && evt.preventDefault(); - this.setState({ showApplicationRefreshModal: false }); - }; - renderApplicationRefreshModal() { const { classes } = this.props; return ( Close @@ -522,17 +302,23 @@ class SelfkeyIdApplicationsComponent extends Component { ); } - handleAccessClick = _ => this.props.dispatch(push(MARKETPLACE_ROOT_PATH)); - render() { - const { classes, isLoading, processing } = this.props; - const { showApplicationRefreshModal } = this.state; - let loading = isLoading || processing || this.state.loading; + const { classes, showApplicationRefreshModal, loading, config } = this.props; if (loading) { return this.renderLoadingScreen(); } + const getRpInfo = (rpName, field) => { + return config.relyingPartyInfo[rpName][field]; + }; + + const getRpName = title => { + return title.toLowerCase().startsWith('bank account') + ? 'Bank Accounts' + : 'Incorporations'; + }; + if (!loading && this.props.applications && this.props.applications.length === 0) { return ( @@ -562,7 +348,7 @@ class SelfkeyIdApplicationsComponent extends Component { @@ -349,7 +291,7 @@ class SelfkeyIdOverviewComponent extends Component { - diff --git a/src/renderer/wallet/main/index.jsx b/src/renderer/wallet/main/index.jsx index cb1e13812..197997297 100644 --- a/src/renderer/wallet/main/index.jsx +++ b/src/renderer/wallet/main/index.jsx @@ -1,6 +1,5 @@ import React, { Component } from 'react'; import { Route } from 'react-router-dom'; -import { push } from 'connected-react-router'; import Dashboard from '../../dashboard'; import { CryptoMangerContainer, AddTokenContainer } from '../../crypto-manager'; import AddressBook from '../../address-book/main'; @@ -88,16 +87,6 @@ class Main extends Component { this.setMatomoId(); } - createPersonalProfile = evt => { - evt && evt.preventDefault(); - this.props.dispatch(push('/selfKeyIdCreate')); - }; - - createCorporateProfile = evt => { - evt && evt.preventDefault(); - this.props.dispatch(push('/main/create-corporate-profile')); - }; - render() { const { match, classes } = this.props; return ( diff --git a/src/renderer/wallet/main/toolbar-container.jsx b/src/renderer/wallet/main/toolbar-container.jsx index 53ff6e964..141c05208 100644 --- a/src/renderer/wallet/main/toolbar-container.jsx +++ b/src/renderer/wallet/main/toolbar-container.jsx @@ -1,24 +1,9 @@ import React, { Component } from 'react'; import Toolbar from './toolbar'; import config from 'common/config'; - -const profiles = [ - { - id: 1, - name: 'James Bond', - type: 'individual' - }, - { - id: 2, - name: 'Acme Corp', - type: 'corporate' - }, - { - id: 3, - name: 'Standard United Bank', - type: 'corporate' - } -]; +import { connect } from 'react-redux'; +import { identitySelectors, identityOperations } from 'common/identity'; +import { push } from 'connected-react-router'; class ToolbarContainer extends Component { state = { @@ -40,6 +25,13 @@ class ToolbarContainer extends Component { createCorporateProfile = evt => { this.toggleProfile(!this.state.isProfileOpen); + this.props.dispatch(push('/main/create-corporate-profile')); + }; + + handleProfileSelect = identity => evt => { + evt.preventDefault(); + this.toggleProfile(!this.state.isProfileOpen); + this.props.dispatch(identityOperations.switchProfileOperation(identity)); }; handleProfileClick = evt => { @@ -51,9 +43,10 @@ class ToolbarContainer extends Component { ({ + profiles: identitySelectors.selectAllIdentities(state) || [], + selectedProfile: identitySelectors.selectCurrentIdentity(state) || {} +}))(ToolbarContainer); diff --git a/src/renderer/wallet/main/toolbar.jsx b/src/renderer/wallet/main/toolbar.jsx index baf1050c9..7b902cc2a 100644 --- a/src/renderer/wallet/main/toolbar.jsx +++ b/src/renderer/wallet/main/toolbar.jsx @@ -113,7 +113,8 @@ const profileStyle = theme => justifyContent: 'center' }, profileDetail: { - paddingBottom: '20px' + paddingBottom: '20px', + cursor: 'pointer' }, profileName: { paddingLeft: '28px' @@ -123,19 +124,29 @@ const profileStyle = theme => } }); +const defaultIdentityName = ({ type }) => + type === 'individual' ? 'New individual' : 'New company'; + const ProfileList = withStyles(profileStyle)( - ({ classes, profiles, isOpen, onClickPersonal, onClickCorporate }) => { + ({ classes, profiles, isOpen, onProfileSelect, onClickCorporate }) => { return ( isOpen && (
{profiles && profiles.map((el, index) => ( - + - {el.type === 'company' ? : } + {el.type === 'corporate' ? : } - {el.name} + + {el.name || defaultIdentityName(el)} + {`${el.type.charAt(0).toUpperCase() + el.type.slice(1)} Profile`} @@ -175,7 +186,7 @@ const Profile = withStyles(styles)(({ classes, profile, isOpen, onProfileClick } {profile.type === 'individual' ? : } - {profile.name} + {profile.name || defaultIdentityName(profile)} {profile.type === 'individual' ? 'Personal Profile' : 'Corporate Profile'} @@ -200,6 +211,7 @@ class Toolbar extends Component { isProfileOpen, selectedProfile, onProfileClick, + onProfileSelect, profiles, onCreateCorporateProfileClick, primaryToken @@ -259,6 +271,7 @@ class Toolbar extends Component { profiles={profiles} isOpen={isProfileOpen} onClickCorporate={onCreateCorporateProfileClick} + onProfileSelect={onProfileSelect} />
diff --git a/stories/corporate.stories.js b/stories/corporate.stories.js index 401f880a5..a4afd1032 100644 --- a/stories/corporate.stories.js +++ b/stories/corporate.stories.js @@ -41,6 +41,4 @@ const dummyMembers = [ } ]; -storiesOf('Corporate', module).add('Corporate/Wizard', () => ( - -)); +storiesOf('Corporate', module).add('Wizard', () => ); diff --git a/stories/sidebar.stories.js b/stories/sidebar.stories.js index 08fe02251..75c61e666 100644 --- a/stories/sidebar.stories.js +++ b/stories/sidebar.stories.js @@ -32,6 +32,7 @@ storiesOf('Sidebars/Toolbar', module) isProfileOpen={false} onToggleMenu={action('onToggleMenu')} onProfileClick={action('onProfileClick')} + onProfileSelect={identity => () => action(`profile switch ${identity.id}`)} onCreateCorporateProfileClick={action('onCreateCorporateProfileClick')} /> )) @@ -44,6 +45,7 @@ storiesOf('Sidebars/Toolbar', module) isProfileOpen={false} onToggleMenu={action('onToggleMenu')} onProfileClick={action('onProfileClick')} + onProfileSelect={identity => () => action(`profile switch ${identity.id}`)} onCreateCorporateProfileClick={action('onCreateCorporateProfileClick')} /> )) @@ -56,6 +58,7 @@ storiesOf('Sidebars/Toolbar', module) isProfileOpen={true} onToggleMenu={action('onToggleMenu')} onProfileClick={action('onProfileClick')} + onProfileSelect={identity => () => action(`profile switch ${identity.id}`)} onCreateCorporateProfileClick={action('onCreateCorporateProfileClick')} /> )); From 4f8de0962b32f1ec503734f5f1390f7a0d1d02ee Mon Sep 17 00:00:00 2001 From: Maxim Kovalov Date: Fri, 13 Sep 2019 12:46:39 +0300 Subject: [PATCH 112/207] feat(attr-types): use only individual attributes for individual profiles --- src/common/identity/identity-duck.spec.js | 2 +- src/common/identity/operations.js | 2 +- src/common/identity/selectors.js | 12 ++++++++++-- .../main/containers/create-attribute-popup.js | 2 +- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/common/identity/identity-duck.spec.js b/src/common/identity/identity-duck.spec.js index 3b97b801f..92d95f3df 100644 --- a/src/common/identity/identity-duck.spec.js +++ b/src/common/identity/identity-duck.spec.js @@ -239,7 +239,7 @@ describe('Identity Duck', () => { }, {}); }); it('selectIdAttributeTypes', () => { - expect(identitySelectors.selectIdAttributeTypes(state)).toEqual( + expect(identitySelectors.selectIdAttributeTypes(state, 'individual')).toEqual( testIdAttributeTypes ); }); diff --git a/src/common/identity/operations.js b/src/common/identity/operations.js index 93dde08a2..12c0abddf 100644 --- a/src/common/identity/operations.js +++ b/src/common/identity/operations.js @@ -130,7 +130,7 @@ const unlockIdentityOperation = identityId => async (dispatch, getState) => { }; const createSelfkeyIdOperation = (identityId, data) => async (dispatch, getState) => { - const idAttributeTypes = identitySelectors.selectIdAttributeTypes(getState()); + const idAttributeTypes = identitySelectors.selectIdAttributeTypes(getState(), 'individual'); const identity = identitySelectors.selectIdentityById(getState(), identityId); const getTypeId = url => { return idAttributeTypes.find(idAttributeType => idAttributeType.url === url).id; diff --git a/src/common/identity/selectors.js b/src/common/identity/selectors.js index aeb383a68..1cba22ba8 100644 --- a/src/common/identity/selectors.js +++ b/src/common/identity/selectors.js @@ -47,13 +47,21 @@ const selectExpiredRepositories = state => { .filter(repo => forceUpdateAttributes || repo.expires <= now); }; -const selectIdAttributeTypes = state => +const selectIdAttributeTypes = (state, entityType = 'individual') => identitySelectors .selectIdentity(state) .idAtrributeTypes.map( id => identitySelectors.selectIdentity(state).idAtrributeTypesById[id] ) - .filter(t => t && t.content); + .filter(t => { + if (!t || !t.content) return false; + + if (!t.entityType && entityType !== 'individual') { + return false; + } + + return t.entityType.includes(entityType); + }); const selectExpiredIdAttributeTypes = state => { let now = Date.now(); diff --git a/src/renderer/selfkey-id/main/containers/create-attribute-popup.js b/src/renderer/selfkey-id/main/containers/create-attribute-popup.js index 7ba66dbd8..c801d6889 100644 --- a/src/renderer/selfkey-id/main/containers/create-attribute-popup.js +++ b/src/renderer/selfkey-id/main/containers/create-attribute-popup.js @@ -72,7 +72,7 @@ class CreateAttributePopupComponent extends Component { const mapStateToProps = (state, props) => { return { - types: identitySelectors.selectIdAttributeTypes(state), + types: identitySelectors.selectIdAttributeTypes(state, 'individual'), uiSchemas: identitySelectors.selectUiSchemas(state) }; }; From ecd898a704499bab43516e4eefaaa117a043ef60 Mon Sep 17 00:00:00 2001 From: Andre Goncalves Date: Sat, 14 Sep 2019 09:48:02 +0100 Subject: [PATCH 113/207] fix: add missing return in async function --- src/main/marketplace/tax-treaties/tax-treaties-service.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/marketplace/tax-treaties/tax-treaties-service.js b/src/main/marketplace/tax-treaties/tax-treaties-service.js index 52360dc3e..20c9fe251 100644 --- a/src/main/marketplace/tax-treaties/tax-treaties-service.js +++ b/src/main/marketplace/tax-treaties/tax-treaties-service.js @@ -96,7 +96,7 @@ export class TaxTreatiesService { } } async deleteMany(ids) { - TaxTreaties.deleteMany(ids); + return TaxTreaties.deleteMany(ids); } } From 5bc102506c1cf34bcb20de38d1c627737ee910d9 Mon Sep 17 00:00:00 2001 From: Andre Goncalves Date: Sat, 14 Sep 2019 10:05:38 +0100 Subject: [PATCH 114/207] fix: move async upsert logic into model --- .../tax-treaties/tax-treaties-service.js | 8 ++--- .../marketplace/tax-treaties/tax-treaties.js | 35 ++++++++++++++----- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/src/main/marketplace/tax-treaties/tax-treaties-service.js b/src/main/marketplace/tax-treaties/tax-treaties-service.js index 20c9fe251..ecbcf3aa9 100644 --- a/src/main/marketplace/tax-treaties/tax-treaties-service.js +++ b/src/main/marketplace/tax-treaties/tax-treaties-service.js @@ -1,7 +1,7 @@ import config from 'common/config'; import { TaxTreaties } from './tax-treaties'; import request from 'request-promise-native'; -import { isDevMode, mapKeysAsync, setImmediatePromise, arrayChunks } from 'common/utils/common'; +import { isDevMode, mapKeysAsync, setImmediatePromise } from 'common/utils/common'; import _ from 'lodash'; import { Logger } from '../../../common/logger'; import { TAX_TREATIES_SYNC_JOB } from './tax-treaties-sync-job-handler'; @@ -89,11 +89,7 @@ export class TaxTreatiesService { return TaxTreaties.findAll(); } async upsert(upsert) { - const chunks = arrayChunks(upsert, 100); - for (const c of chunks) { - TaxTreaties.bulkUpsert(c); - await setImmediatePromise(); - } + return TaxTreaties.bulkUpsert(upsert); } async deleteMany(ids) { return TaxTreaties.deleteMany(ids); diff --git a/src/main/marketplace/tax-treaties/tax-treaties.js b/src/main/marketplace/tax-treaties/tax-treaties.js index c26fc5157..b15bdf50e 100644 --- a/src/main/marketplace/tax-treaties/tax-treaties.js +++ b/src/main/marketplace/tax-treaties/tax-treaties.js @@ -1,5 +1,6 @@ import BaseModel from '../../common/base-model'; -import { isDevMode, isTestMode } from 'common/utils/common'; +import { transaction } from 'objection'; +import { isDevMode, isTestMode, setImmediatePromise, arrayChunks } from 'common/utils/common'; const TABLE_NAME = 'tax_treaties'; const env = isTestMode() ? 'test' : isDevMode() ? 'development' : 'production'; export class TaxTreaties extends BaseModel { @@ -57,15 +58,33 @@ export class TaxTreaties extends BaseModel { return this.insertMany(items); } - static async bulkUpsert(items) { - const insert = items.filter(item => !item.hasOwnProperty(this.idColumn)); - const update = items.filter(item => item.hasOwnProperty(this.idColumn)); + static async bulkUpsert(items, chunkSize = 100) { + let foundItems = []; + const chunks = arrayChunks(items, chunkSize); - let all = await this.bulkAdd(insert); - all = all.concat(await this.bulkEdit(update)); + const tx = await transaction.start(this.knex()); + try { + for (const chunk of chunks) { + const insert = chunk.filter(item => !item.hasOwnProperty(this.idColumn)); + const update = chunk.filter(item => item.hasOwnProperty(this.idColumn)); - let found = await this.findAll(); - return found.filter(x => all.find(t => t[this.idColumn] === x[this.idColumn])); + let all = await this.bulkAdd(insert); + all = all.concat(await this.bulkEdit(update)); + + let found = await this.findAll(); + foundItems = [ + ...foundItems, + ...found.filter(x => all.find(t => t[this.idColumn] === x[this.idColumn])) + ]; + + await setImmediatePromise(); + } + await tx.commit(); + } catch (error) { + await tx.rollback(); + throw error; + } + return foundItems; } } From 5b9b93f2a1f58a33d4f76728d3621d0d2db061b2 Mon Sep 17 00:00:00 2001 From: Andre Goncalves Date: Sat, 14 Sep 2019 10:41:19 +0100 Subject: [PATCH 115/207] fix: passing outer transaction to bulk operations --- .../marketplace/tax-treaties/tax-treaties.js | 27 +++++++++---------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/src/main/marketplace/tax-treaties/tax-treaties.js b/src/main/marketplace/tax-treaties/tax-treaties.js index b15bdf50e..cdaa16a99 100644 --- a/src/main/marketplace/tax-treaties/tax-treaties.js +++ b/src/main/marketplace/tax-treaties/tax-treaties.js @@ -48,18 +48,18 @@ export class TaxTreaties extends BaseModel { return this.query().patchAndFetchById(id, data); } - static bulkEdit(items) { + static bulkEdit(items, tx = undefined) { items = items.map(item => ({ ...item, env })); - return this.updateMany(items); + return this.updateMany(items, tx); } - static bulkAdd(items) { + static async bulkAdd(items, tx = undefined) { items = items.map(item => ({ ...item, env })); - return this.insertMany(items); + return this.insertMany(items, tx); } static async bulkUpsert(items, chunkSize = 100) { - let foundItems = []; + let all = []; const chunks = arrayChunks(items, chunkSize); const tx = await transaction.start(this.knex()); @@ -68,23 +68,20 @@ export class TaxTreaties extends BaseModel { const insert = chunk.filter(item => !item.hasOwnProperty(this.idColumn)); const update = chunk.filter(item => item.hasOwnProperty(this.idColumn)); - let all = await this.bulkAdd(insert); - all = all.concat(await this.bulkEdit(update)); - - let found = await this.findAll(); - foundItems = [ - ...foundItems, - ...found.filter(x => all.find(t => t[this.idColumn] === x[this.idColumn])) - ]; - + all = all.concat(await this.bulkAdd(insert, tx)); + all = all.concat(await this.bulkEdit(update, tx)); await setImmediatePromise(); } await tx.commit(); + const found = await this.findAll(); + const foundItems = found.filter(x => + all.find(t => t[this.idColumn] === x[this.idColumn]) + ); + return foundItems; } catch (error) { await tx.rollback(); throw error; } - return foundItems; } } From a4054864e69da22a7251770d85383dff7de37a4c Mon Sep 17 00:00:00 2001 From: Maxim Kovalov Date: Mon, 16 Sep 2019 06:27:46 +0300 Subject: [PATCH 116/207] feat(identity): fix bugs --- src/common/identity/operations.js | 13 ++++++++++++- src/common/identity/types.js | 3 ++- src/main/identity/identity-service.js | 1 + .../bank-accounts/details/details-container.jsx | 2 +- .../selfkey-id/main/components/associate-did.jsx | 6 ++++-- 5 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/common/identity/operations.js b/src/common/identity/operations.js index 93dde08a2..bc931b2a0 100644 --- a/src/common/identity/operations.js +++ b/src/common/identity/operations.js @@ -179,6 +179,12 @@ const loadIdentitiesOperation = walletId => async (dispatch, getState) => { await dispatch(identityActions.setIdentitiesAction(identities)); }; +const updateDIDOperation = (did, id) => async (dispatch, getState) => { + const identityService = getGlobalContext().identityService; + const identity = await identityService.updateIdentityDID(did, id); + await dispatch(identityActions.updateIdentity(identity)); +}; + export const operations = { loadCountriesOperation, loadRepositoriesOperation, @@ -199,7 +205,8 @@ export const operations = { updateProfilePictureOperation, createSelfkeyIdOperation, loadIdentitiesOperation, - updateIdentitySetupOperation + updateIdentitySetupOperation, + updateDIDOperation }; export const identityOperations = { @@ -283,6 +290,10 @@ export const identityOperations = { updateIdentitySetupOperation: createAliasedAction( identityTypes.IDENTITIES_UPDATE_SETUP_OPERATION, operations.updateIdentitySetupOperation + ), + updateDIDOperation: createAliasedAction( + identityTypes.IDENTITIES_UPDATE_DID_OPERATION, + operations.updateDIDOperation ) }; diff --git a/src/common/identity/types.js b/src/common/identity/types.js index d997b1760..a26b79472 100644 --- a/src/common/identity/types.js +++ b/src/common/identity/types.js @@ -38,7 +38,8 @@ export const identityTypes = { IDENTITY_UPDATE: 'identity/UPDATE', IDENTITIES_LOAD: 'identities/LOAD', IDENTITY_CURRENT_SET: 'identities/current/SET', - IDENTITIES_UPDATE_SETUP_OPERATION: 'identities/setup/UPDATE' + IDENTITIES_UPDATE_SETUP_OPERATION: 'identities/setup/UPDATE', + IDENTITIES_UPDATE_DID_OPERATION: 'identities/did/UPDATE' }; export default identityTypes; diff --git a/src/main/identity/identity-service.js b/src/main/identity/identity-service.js index afd86c385..fd9e10f60 100644 --- a/src/main/identity/identity-service.js +++ b/src/main/identity/identity-service.js @@ -129,6 +129,7 @@ export class IdentityService { } updateIdentityDID(did, id) { + did = did.replace('did:selfkey:', ''); return Identity.updateDID({ did, id }); } } diff --git a/src/renderer/marketplace/bank-accounts/details/details-container.jsx b/src/renderer/marketplace/bank-accounts/details/details-container.jsx index 478568b49..8360a8fc3 100644 --- a/src/renderer/marketplace/bank-accounts/details/details-container.jsx +++ b/src/renderer/marketplace/bank-accounts/details/details-container.jsx @@ -100,7 +100,7 @@ class BankAccountsDetailContainer extends MarketplaceBankAccountsComponent { const maxFromCurrencyString = (accounts, field) => { return Object.keys(accounts).reduce((current, accountId) => { const account = accounts[accountId]; - const item = Number(account[field].replace(/[^0-9.-]+/g, '')); + const item = Number((account[field] || '0').replace(/[^0-9.-]+/g, '')); return current > item ? current : item; }, 0); }; diff --git a/src/renderer/selfkey-id/main/components/associate-did.jsx b/src/renderer/selfkey-id/main/components/associate-did.jsx index 6ae6947bf..01eba413d 100644 --- a/src/renderer/selfkey-id/main/components/associate-did.jsx +++ b/src/renderer/selfkey-id/main/components/associate-did.jsx @@ -2,7 +2,7 @@ import React, { Component } from 'react'; import { push } from 'connected-react-router'; import { connect } from 'react-redux'; import { walletOperations, walletSelectors } from 'common/wallet'; -import { identityOperations, identitySelectors } from 'common/identity'; +import { identitySelectors } from 'common/identity'; import { Grid, Button, @@ -115,7 +115,9 @@ class AssociateDIDComponent extends Component { await this.resetErrors(); let did = this.state.did; if (did !== '') { - await this.props.dispatch(identityOperations.updateDID(this.props.identity.id, did)); + await this.props.dispatch( + walletOperations.updateWalletDID(this.props.identity.walletId, did) + ); } else { this.setState({ searching: false }); } From a6c9ea2dfb67908fb722f47c1b1117e2348467de Mon Sep 17 00:00:00 2001 From: Maxim Kovalov Date: Mon, 16 Sep 2019 07:30:15 +0300 Subject: [PATCH 117/207] feat(attribute-types): fix selectors --- src/common/identity/selectors.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/identity/selectors.js b/src/common/identity/selectors.js index 1cba22ba8..00be857ad 100644 --- a/src/common/identity/selectors.js +++ b/src/common/identity/selectors.js @@ -56,11 +56,11 @@ const selectIdAttributeTypes = (state, entityType = 'individual') => .filter(t => { if (!t || !t.content) return false; - if (!t.entityType && entityType !== 'individual') { + if (!t.content.entityType && entityType !== 'individual') { return false; } - return t.entityType.includes(entityType); + return (t.content.entityType || ['individual']).includes(entityType); }); const selectExpiredIdAttributeTypes = state => { From 1322e0e01935a403d4e62f03b765d1830b7cd118 Mon Sep 17 00:00:00 2001 From: Andre Goncalves Date: Mon, 16 Sep 2019 09:30:46 +0100 Subject: [PATCH 118/207] feat: legend for shareholding graph --- .../common/corporate-shareholding.jsx | 40 ++++++++++++++++--- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/src/renderer/corporate/common/corporate-shareholding.jsx b/src/renderer/corporate/common/corporate-shareholding.jsx index 3c12a9669..1615228ca 100644 --- a/src/renderer/corporate/common/corporate-shareholding.jsx +++ b/src/renderer/corporate/common/corporate-shareholding.jsx @@ -1,7 +1,6 @@ import React from 'react'; import { Grid, CardHeader, Card, CardContent, Typography } from '@material-ui/core'; import { Chart } from 'react-google-charts'; -import { CheckMaIcon, AttributeAlertIcon, EditTransparentIcon } from 'selfkey-ui'; import { withStyles } from '@material-ui/core'; const styles = theme => ({ @@ -39,16 +38,39 @@ const styles = theme => ({ marginRight: '0.5em', verticalAlign: 'middle' } + }, + legend: { + alignSelf: 'flex-end', + marginBottom: '1em', + '& > div': { + display: 'flex', + alignItems: 'center', + marginTop: '0.5em' + }, + '& span': { + marginLeft: '0.5em' + } + }, + coloredBox: { + width: '22px !important', + height: '8px !important', + borderRadius: '8px !important', + position: 'relative' } }); +const getColors = () => { + // TODO: generate random colors algorithm to account for unknown number of shareholders + return ['#46dfba', '#46b7df', '#238db4', '#1d7999', '#0e4b61']; +}; + const chartOptions = { backgroundColor: 'transparent', title: '', chartArea: { left: 15, top: 15, bottom: 15, right: 15 }, pieHole: 0.7, pieSliceBorderColor: 'none', - colors: ['#46dfba', '#46b7df', '#238db4', '#1d7999', '#0e4b61'], + colors: getColors(), legend: { position: 'none' }, @@ -62,9 +84,7 @@ const chartOptions = { const getChartData = cap => { const data = [['Content', 'percents']]; - console.log(cap); const dataPoints = cap.map(shareholder => [shareholder.name, shareholder.shares]); - console.log(data.concat(dataPoints)); return data.concat(dataPoints); }; @@ -111,7 +131,17 @@ const CorporateShareholding = withStyles(styles)(props => { }} />
- + + {cap.map((shareholder, index) => ( +
+
+ {shareholder.name} +
+ ))} + From fe745c01b460d32457ea9d3d3f62e7e8e9394971 Mon Sep 17 00:00:00 2001 From: Andre Goncalves Date: Mon, 16 Sep 2019 10:48:31 +0100 Subject: [PATCH 119/207] feat: react org chart --- package.json | 1 + .../corporate/common/corporate-org-chart.jsx | 98 +++++++++++++++++++ .../corporate/common/corporate-structure.jsx | 0 stories/corporate-data.js | 63 ++++++------ stories/corporate.stories.js | 6 +- yarn.lock | 5 + 6 files changed, 142 insertions(+), 31 deletions(-) create mode 100644 src/renderer/corporate/common/corporate-org-chart.jsx delete mode 100644 src/renderer/corporate/common/corporate-structure.jsx diff --git a/package.json b/package.json index cb1535b54..b8dcfbed5 100644 --- a/package.json +++ b/package.json @@ -101,6 +101,7 @@ "react-dom": "16.6.3", "react-jsonschema-form": "https://github.com/SelfKeyFoundation/react-jsonschema-form.git#57c07f0842f649baaf484e014a5069f55aca8b4f", "react-jsonschema-form-material-theme": "https://github.com/SelfKeyFoundation/react-jsonschema-form-material-theme.git#c7bee22fde632cebce3dbcd9a168d9592d585dd7", + "react-orgchart": "^1.0.5", "react-piwik": "1.6.0", "react-redux": "6.0.1", "react-router-dom": "5.0.0", diff --git a/src/renderer/corporate/common/corporate-org-chart.jsx b/src/renderer/corporate/common/corporate-org-chart.jsx new file mode 100644 index 000000000..b763f4b3c --- /dev/null +++ b/src/renderer/corporate/common/corporate-org-chart.jsx @@ -0,0 +1,98 @@ +import React from 'react'; +import { Grid, CardHeader, Card, CardContent } from '@material-ui/core'; +import { base, grey, EditTransparentIcon } from 'selfkey-ui'; +import { withStyles } from '@material-ui/core'; +import 'react-orgchart/index.css'; +import OrgChart from 'react-orgchart'; + +const styles = theme => ({ + hr: { + backgroundColor: `${base}`, + border: 'none', + boxSizing: 'border-box', + height: '1px', + margin: '5px 16px' + }, + card: {}, + cardHeader: { + whiteSpace: 'normal', + wordBreak: 'break-all' + }, + regularText: { + '& span': { + fontWeight: 400 + } + }, + orgChart: { + overflow: 'auto', + margin: 'auto', + '& .initechNode': { + border: `solid 1px ${grey}`, + borderRadius: '3px', + padding: '1em', + width: '150px', + display: 'inline-block', + margin: '0 2px' + }, + '& .initechNode span': { + display: 'block', + color: `${grey}`, + fontSize: '12px', + marginTop: '0.5em' + }, + '& .orgNodeChildGroup .nodeLineTable .nodeGroupLineVerticalMiddle': { + borderRight: `solid 1px ${grey}` + }, + '& .nodeLineTable .nodeLineBorderTop': { + borderTop: `solid 1px ${grey}` + } + } +}); + +const generateStructFromCap = (name, cap) => { + return { + name: name, + role: 'Entity', + children: cap + }; +}; + +const editAction = onEdit => ( +
+ +
+); + +const treeNode = ({ node }) => ( +
+ {node.name} + {node.role} +
+); + +const CorporateOrgChart = withStyles(styles)(props => { + const { classes, name, cap = [], onEdit } = props; + return ( + + + + +
+ + + +
+
+
+ ); +}); + +export { CorporateOrgChart }; +export default CorporateOrgChart; diff --git a/src/renderer/corporate/common/corporate-structure.jsx b/src/renderer/corporate/common/corporate-structure.jsx deleted file mode 100644 index e69de29bb..000000000 diff --git a/stories/corporate-data.js b/stories/corporate-data.js index ca71d7d8e..00a05640c 100644 --- a/stories/corporate-data.js +++ b/stories/corporate-data.js @@ -16,36 +16,6 @@ export const corporateApplications = [ } ]; -export const corporateCapTable = [ - { - type: 'Person', - role: 'Director', - name: 'John Doe', - email: 'john.doe@email.com', - citizenship: 'Italy', - residency: 'Singapore', - shares: 0.5 - }, - { - type: 'Corporate', - role: 'Shareholder', - name: 'ACME Inc', - email: null, - citizenship: 'Hong Kong', - residency: 'Hong Kong', - shares: 0.09 - }, - { - type: 'Corporate', - role: 'Shareholder', - name: 'Apple Inc', - email: null, - citizenship: 'U.S.A.', - residency: 'U.S.A.', - shares: 0.41 - } -]; - export const dummyMembers = [ { id: '1', @@ -84,3 +54,36 @@ export const dummyMembers = [ shares: '5%' } ]; + +export const corporateCapTable = [ + { + type: 'Person', + role: 'Director', + name: 'John Doe', + email: 'john.doe@email.com', + citizenship: 'Italy', + residency: 'Singapore', + shares: 0.5, + children: [] + }, + { + type: 'Corporate', + role: 'Shareholder', + name: 'ACME Inc', + email: null, + citizenship: 'Hong Kong', + residency: 'Hong Kong', + shares: 0.09, + children: dummyMembers + }, + { + type: 'Corporate', + role: 'Shareholder', + name: 'Apple Inc', + email: null, + citizenship: 'U.S.A.', + residency: 'U.S.A.', + shares: 0.41, + children: [] + } +]; diff --git a/stories/corporate.stories.js b/stories/corporate.stories.js index f4118b0f9..15812a3ac 100644 --- a/stories/corporate.stories.js +++ b/stories/corporate.stories.js @@ -9,6 +9,7 @@ import { CorporateDetails } from '../src/renderer/corporate/common/corporate-det import { CorporateApplicationsSummary } from '../src/renderer/corporate/common/corporate-applications'; import { CorporateCapTable } from '../src/renderer/corporate/common/corporate-cap-table'; import { CorporateShareholding } from '../src/renderer/corporate/common/corporate-shareholding'; +import { CorporateOrgChart } from '../src/renderer/corporate/common/corporate-org-chart'; import { CorporateWizard } from '../src/renderer/corporate/wizard/corporate-wizard'; import { corporateApplications, corporateCapTable, dummyMembers } from './corporate-data'; @@ -79,6 +80,9 @@ storiesOf('Corporate/Blocks', module) .add('Corporate Cap Table', () => ( )) - .add('Corporate Shareholding', () => ); + .add('Corporate Shareholding', () => ) + .add('Corporate Org Chart', () => ( + + )); storiesOf('Corporate', module).add('Wizard', () => ); diff --git a/yarn.lock b/yarn.lock index 27e3a08eb..e5d30c8b0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -17654,6 +17654,11 @@ react-onclickoutside@^6.5.0: resolved "https://registry.yarnpkg.com/react-onclickoutside/-/react-onclickoutside-6.8.0.tgz#9f91b5b3ed59f4d9e43fd71620dc200773a4d569" integrity sha512-5Q4Rn7QLEoh7WIe66KFvYIpWJ49GeHoygP1/EtJyZjXKgrWH19Tf0Ty3lWyQzrEEDyLOwUvvmBFSE3dcDdvagA== +react-orgchart@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/react-orgchart/-/react-orgchart-1.0.5.tgz#49da6714ed12926315c79744cd7f8bed18f1e915" + integrity sha1-SdpnFO0SkmMVx5dEzX+L7Rjx6RU= + react-piwik@1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/react-piwik/-/react-piwik-1.6.0.tgz#3b9eee55167d953824867791cd5288593d652d66" From 061567390a7c006a0f50b2b82d12d2466ea6f3ed Mon Sep 17 00:00:00 2001 From: Eduardo Santiago Moura Date: Mon, 16 Sep 2019 21:48:06 -0300 Subject: [PATCH 120/207] feat(corp): add members ui to storybook --- .gitignore | 1 + src/main/main-window.js | 2 +- .../member/corporate-add-member-container.jsx | 77 +++++++++++++++++++ .../member/corporate-add-member.jsx} | 65 ++++------------ src/renderer/wallet/main/index.jsx | 6 +- stories/corporate.stories.js | 3 + 6 files changed, 101 insertions(+), 53 deletions(-) create mode 100644 src/renderer/corporate/member/corporate-add-member-container.jsx rename src/renderer/{selfkey-id/main/components/add-company-member.jsx => corporate/member/corporate-add-member.jsx} (92%) diff --git a/.gitignore b/.gitignore index 9521095b8..757681edd 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,7 @@ dist/ src/renderer/angular/app.templates.js static/stylesheets/css/main.css static/stylesheets/css/* +storybook-static/ client-secret.json **/.env diff --git a/src/main/main-window.js b/src/main/main-window.js index d56f9586c..f0476024b 100644 --- a/src/main/main-window.js +++ b/src/main/main-window.js @@ -51,7 +51,7 @@ export const createMainWindow = () => { mainWindow.loadURL(webAppPath); - mainWindow.setMenu(null); // in order to don't show electron default menu bar + // mainWindow.setMenu(null); // in order to don't show electron default menu bar if (isDebugMode()) { log.info('app is running in debug mode'); diff --git a/src/renderer/corporate/member/corporate-add-member-container.jsx b/src/renderer/corporate/member/corporate-add-member-container.jsx new file mode 100644 index 000000000..a8e9da62e --- /dev/null +++ b/src/renderer/corporate/member/corporate-add-member-container.jsx @@ -0,0 +1,77 @@ +import React, { Component } from 'react'; +import { CorporateAddMember } from './corporate-add-member'; +import { connect } from 'react-redux'; +import { addressBookSelectors, addressBookOperations } from 'common/address-book'; +import { withStyles } from '@material-ui/core/styles'; +import { push } from 'connected-react-router'; + +const styles = theme => ({ + radioBoxContainer: { + margin: '10px 0 40px' + } +}); + +class CorporateAddMemberContainer extends Component { + state = { + label: '', + address: '' + }; + + componentDidMount() { + this.props.dispatch(addressBookOperations.resetAdd()); + } + + handleSubmit = event => { + event.preventDefault(); + return this.handleSave(this.state.label, this.state.address); + }; + + handleSave = async (label, address) => { + await this.props.dispatch(addressBookOperations.addAddressBookEntry({ label, address })); + this.closeAction(); + }; + + handleLabelChange = event => { + event.preventDefault(); + const label = event.target.value; + this.setState({ + ...this.state, + label + }); + this.props.dispatch(addressBookOperations.validateLabel(label)); + }; + + handleAddressChange = event => { + event.preventDefault(); + const address = event.target.value; + this.setState({ + ...this.state, + address + }); + this.props.dispatch(addressBookOperations.validateAddress(address)); + }; + + closeAction = () => { + this.props.dispatch(push('/main/create-corporate-profile')); + }; + + render() { + return ( + + ); + } +} + +const mapStateToProps = (state, props) => { + return { + labelError: addressBookSelectors.getLabelError(state), + addressError: addressBookSelectors.getAddressError(state) + }; +}; + +const styledComponent = withStyles(styles)(CorporateAddMemberContainer); +export default connect(mapStateToProps)(styledComponent); diff --git a/src/renderer/selfkey-id/main/components/add-company-member.jsx b/src/renderer/corporate/member/corporate-add-member.jsx similarity index 92% rename from src/renderer/selfkey-id/main/components/add-company-member.jsx rename to src/renderer/corporate/member/corporate-add-member.jsx index 7509732e3..eba440d06 100644 --- a/src/renderer/selfkey-id/main/components/add-company-member.jsx +++ b/src/renderer/corporate/member/corporate-add-member.jsx @@ -1,5 +1,4 @@ import React, { Component } from 'react'; -import { connect } from 'react-redux'; import { ModalWrap, ModalCloseButton, @@ -12,11 +11,9 @@ import { ProfileIcon, CompanyIcon } from 'selfkey-ui'; -import { addressBookSelectors, addressBookOperations } from 'common/address-book'; import { Grid, Modal, Typography, Input, Select, MenuItem } from '@material-ui/core'; import { KeyboardArrowDown } from '@material-ui/icons'; import { withStyles } from '@material-ui/core/styles'; -import { push } from 'connected-react-router'; const styles = theme => ({ errorText: { @@ -130,48 +127,24 @@ const styles = theme => ({ } }); -class AddCompanyMemberContainer extends Component { +class CorporateAddMemberComponent extends Component { state = { - label: '', - address: '' + error: '', + errorEmail: false, + nickName: '', + firstName: '', + lastName: '', + email: '', + isDisabled: true }; - componentDidMount() { - this.props.dispatch(addressBookOperations.resetAdd()); - } - - handleSubmit = event => { - event.preventDefault(); - return this.handleSave(this.state.label, this.state.address); - }; - - handleSave = async (label, address) => { - await this.props.dispatch(addressBookOperations.addAddressBookEntry({ label, address })); - this.closeAction(); - }; - - handleLabelChange = event => { - event.preventDefault(); - const label = event.target.value; - this.setState({ - ...this.state, - label + handleEmailChange = event => { + this.setState({ email: event.target.value }, () => { + let valid = this.isValidEmail(this.state.email); + this.setState({ errorEmail: !valid }, () => { + this.isDisabled(); + }); }); - this.props.dispatch(addressBookOperations.validateLabel(label)); - }; - - handleAddressChange = event => { - event.preventDefault(); - const address = event.target.value; - this.setState({ - ...this.state, - address - }); - this.props.dispatch(addressBookOperations.validateAddress(address)); - }; - - closeAction = () => { - this.props.dispatch(push('/main/create-corporate-profile')); }; render() { @@ -767,12 +740,6 @@ class AddCompanyMemberContainer extends Component { } } -const mapStateToProps = (state, props) => { - return { - labelError: addressBookSelectors.getLabelError(state), - addressError: addressBookSelectors.getAddressError(state) - }; -}; +export const CorporateAddMember = withStyles(styles)(CorporateAddMemberComponent); -const styledComponent = withStyles(styles)(AddCompanyMemberContainer); -export default connect(mapStateToProps)(styledComponent); +export default CorporateAddMember; diff --git a/src/renderer/wallet/main/index.jsx b/src/renderer/wallet/main/index.jsx index 5c06e6175..c916732bd 100644 --- a/src/renderer/wallet/main/index.jsx +++ b/src/renderer/wallet/main/index.jsx @@ -50,7 +50,7 @@ import CreateDID from '../../selfkey-id/main/components/create-did'; import CreateDIDProcessing from '../../selfkey-id/main/components/create-did-processing'; import HardwareWalletTransactionTimer from '../../transaction/send/timer'; import CorporateWizardContainer from '../../corporate/wizard/corporate-wizard-container'; -import AddCompanyMemberContainer from '../../selfkey-id/main/components/add-company-member'; +import CorporateAddMemberContainer from '../../corporate/member/corporate-add-member-container'; const styles = theme => ({ headerSection: { @@ -227,8 +227,8 @@ class Main extends Component { component={CorporateWizardContainer} /> diff --git a/stories/corporate.stories.js b/stories/corporate.stories.js index f4118b0f9..66fcc295e 100644 --- a/stories/corporate.stories.js +++ b/stories/corporate.stories.js @@ -10,6 +10,7 @@ import { CorporateApplicationsSummary } from '../src/renderer/corporate/common/c import { CorporateCapTable } from '../src/renderer/corporate/common/corporate-cap-table'; import { CorporateShareholding } from '../src/renderer/corporate/common/corporate-shareholding'; import { CorporateWizard } from '../src/renderer/corporate/wizard/corporate-wizard'; +import { CorporateAddMember } from '../src/renderer/corporate/member/corporate-add-member'; import { corporateApplications, corporateCapTable, dummyMembers } from './corporate-data'; @@ -82,3 +83,5 @@ storiesOf('Corporate/Blocks', module) .add('Corporate Shareholding', () => ); storiesOf('Corporate', module).add('Wizard', () => ); + +storiesOf('Corporate', module).add('Add Member', () => ); From 02965b5bf5083648c19660612dc66f7b082a09f5 Mon Sep 17 00:00:00 2001 From: designhorf Date: Tue, 17 Sep 2019 06:15:24 +0200 Subject: [PATCH 121/207] fix: alignment of dropdown and changed icons --- src/renderer/wallet/main/toolbar.jsx | 52 +++++++++++++++++++--------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/src/renderer/wallet/main/toolbar.jsx b/src/renderer/wallet/main/toolbar.jsx index 7b902cc2a..e00a7df64 100644 --- a/src/renderer/wallet/main/toolbar.jsx +++ b/src/renderer/wallet/main/toolbar.jsx @@ -1,6 +1,14 @@ import React, { Component } from 'react'; import { createStyles, withStyles, Button, Grid, Typography } from '@material-ui/core'; -import { MenuNewIcon, DropdownIcon, RoundCompany, RoundPerson } from 'selfkey-ui'; +import { Link } from 'react-router-dom'; +import { + MenuNewIcon, + DropdownIcon, + SmallRoundCompany, + SmallRoundPerson, + RoundCompany, + RoundPerson +} from 'selfkey-ui'; import PriceBox from '../../price-box'; import Sidebar from './sidebar'; @@ -44,6 +52,10 @@ const styles = theme => ({ closedDrawer: { left: '73px' }, + flexLink: { + display: 'flex', + textDecoration: 'none' + }, nameRole: { display: 'flex', flexDirection: 'column', @@ -66,7 +78,7 @@ const styles = theme => ({ width: '100%', position: 'fixed', right: '2%', - top: '78px', + top: '63px', zIndex: '999' }, openedProfile: { @@ -82,10 +94,10 @@ const styles = theme => ({ const profileStyle = theme => createStyles({ profile: { - minWidth: '201px', - maxWidth: '201px', + minWidth: '198px', + maxWidth: '198px', float: 'right', - padding: '20px 20px 8px 20px', + padding: '20px 15px 8px 15px', borderRadius: '4px', backgroundColor: '#1E262E', border: 'solid 1px #303c49' @@ -117,7 +129,7 @@ const profileStyle = theme => cursor: 'pointer' }, profileName: { - paddingLeft: '28px' + paddingLeft: '15px' }, button: { width: '189px' @@ -141,7 +153,11 @@ const ProfileList = withStyles(profileStyle)( onClick={onProfileSelect(el)} > - {el.type === 'corporate' ? : } + {el.type === 'corporate' ? ( + + ) : ( + + )} @@ -184,14 +200,16 @@ const ProfileList = withStyles(profileStyle)( const Profile = withStyles(styles)(({ classes, profile, isOpen, onProfileClick }) => ( - {profile.type === 'individual' ? : } - - {profile.name || defaultIdentityName(profile)} - - {profile.type === 'individual' ? 'Personal Profile' : 'Corporate Profile'} - - - + + {profile.type === 'individual' ? : } + + {profile.name || defaultIdentityName(profile)} + + {profile.type === 'individual' ? 'Personal Profile' : 'Corporate Profile'} + + + + - +
@@ -255,7 +273,7 @@ class Toolbar extends Component { alignItems="center" spacing={0} > - + Date: Tue, 17 Sep 2019 10:20:57 +0200 Subject: [PATCH 122/207] feat: updated Selfkey UI --- package.json | 2 +- yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index cb1535b54..13ca868d4 100644 --- a/package.json +++ b/package.json @@ -113,7 +113,7 @@ "reselect": "4.0.0", "sanitize-html": "1.20.0", "scrypt": "6.0.3", - "selfkey-ui": "https://github.com/SelfKeyFoundation/selfkey-ui.git#27a24b4d3f190ef52fd393a62e8df920d48baf4e", + "selfkey-ui": "https://github.com/SelfKeyFoundation/selfkey-ui.git#f87ee8f6dd6328af28c6985115b669ba94f2002c", "selfkey.js": "1.0.24", "serialize-error": "3.0.0", "snyk": "1.216.0", diff --git a/yarn.lock b/yarn.lock index 27e3a08eb..5d9df7cfb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -18979,9 +18979,9 @@ select@^1.1.2: resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d" integrity sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0= -"selfkey-ui@https://github.com/SelfKeyFoundation/selfkey-ui.git#27a24b4d3f190ef52fd393a62e8df920d48baf4e": +"selfkey-ui@https://github.com/SelfKeyFoundation/selfkey-ui.git#95cfbf2be3fcd5a055bc259a981cab0f251a8db2": version "1.0.0" - resolved "https://github.com/SelfKeyFoundation/selfkey-ui.git#27a24b4d3f190ef52fd393a62e8df920d48baf4e" + resolved "https://github.com/SelfKeyFoundation/selfkey-ui.git#95cfbf2be3fcd5a055bc259a981cab0f251a8db2" dependencies: "@material-ui/core" "3.9.2" "@material-ui/icons" "3.0.2" @@ -19008,11 +19008,10 @@ select@^1.1.2: react-jss "8.6.1" react-truncate "2.4.0" reset-jss "1.0.0" - snyk "^1.193.2" -"selfkey-ui@https://github.com/SelfKeyFoundation/selfkey-ui.git#95cfbf2be3fcd5a055bc259a981cab0f251a8db2": +"selfkey-ui@https://github.com/SelfKeyFoundation/selfkey-ui.git#f87ee8f6dd6328af28c6985115b669ba94f2002c": version "1.0.0" - resolved "https://github.com/SelfKeyFoundation/selfkey-ui.git#95cfbf2be3fcd5a055bc259a981cab0f251a8db2" + resolved "https://github.com/SelfKeyFoundation/selfkey-ui.git#f87ee8f6dd6328af28c6985115b669ba94f2002c" dependencies: "@material-ui/core" "3.9.2" "@material-ui/icons" "3.0.2" @@ -19039,6 +19038,7 @@ select@^1.1.2: react-jss "8.6.1" react-truncate "2.4.0" reset-jss "1.0.0" + snyk "^1.193.2" selfkey.js@1.0.24: version "1.0.24" From 6ea69f600ccd67a3775cf048715be4c28d2e7db9 Mon Sep 17 00:00:00 2001 From: Andre Goncalves Date: Tue, 17 Sep 2019 10:54:40 +0100 Subject: [PATCH 123/207] refactor: override kycc api env vars --- src/common/config.js | 15 ++----- src/common/kyc/index.js | 44 ++++++++++--------- .../components/selfkey-id-applications.jsx | 3 +- 3 files changed, 28 insertions(+), 34 deletions(-) diff --git a/src/common/config.js b/src/common/config.js index 20e9420de..e1f667e88 100644 --- a/src/common/config.js +++ b/src/common/config.js @@ -18,16 +18,16 @@ const PRIMARY_TOKEN = process.env.PRIMARY_TOKEN_OVERRIDE ? process.env.PRIMARY_TOKEN_OVERRIDE.toUpperCase() : null; +// KYCC ENV variables +const KYCC_API_OVERRIDE = process.env.KYCC_API_OVERRIDE; // Incorporations ENV variables const INCORPORATIONS_TEMPLATE_OVERRIDE = process.env.INCORPORATIONS_TEMPLATE_OVERRIDE; const INCORPORATIONS_PRICE_OVERRIDE = process.env.INCORPORATIONS_PRICE_OVERRIDE; -const INCORPORATION_KYCC_INSTANCE = process.env.INCORPORATION_KYCC_INSTANCE; const INCORPORATION_API_URL = process.env.INCORPORATION_API_URL; const INCORPORATION_TREATIES_URL = process.env.INCORPORATION_TREATIES_URL; // Bank Accounts ENV variables const BANKACCOUNTS_TEMPLATE_OVERRIDE = process.env.BANKACCOUNTS_TEMPLATE_OVERRIDE; const BANKACCOUNTS_PRICE_OVERRIDE = process.env.BANKACCOUNTS_PRICE_OVERRIDE; -const BANKACCOUNTS_KYCC_INSTANCE = process.env.BANKACCOUNTS_KYCC_INSTANCE; const BANKACCOUNTS_API_URL = process.env.BANKACCOUNTS_API_URL; const COUNTRY_INFO_URL = process.env.COUNTRY_INFO_URL; @@ -47,16 +47,14 @@ const common = { forceUpdateAttributes: process.env.FORCE_UPDATE_ATTRIBUTES === 'true' && !isTestMode(), userAgent: `SelfKeyIDW/${pkg.version}`, airtableBaseUrl: 'https://us-central1-kycchain-master.cloudfunctions.net/airtable?tableName=', - incorporationsInstance: - INCORPORATION_KYCC_INSTANCE || 'https://dev.instance.kyc-chain.com/api/v2/', + + kyccUrlOverride: KYCC_API_OVERRIDE, incorporationsPriceOverride: INCORPORATIONS_PRICE_OVERRIDE, incorporationsTemplateOverride: INCORPORATIONS_TEMPLATE_OVERRIDE, incorporationApiUrl: INCORPORATION_API_URL || 'https://passports.io/api/incorporations', incorporationTreatiesUrl: INCORPORATION_TREATIES_URL || 'https://passports.io/api/tax-treaties', countryInfoUrl: COUNTRY_INFO_URL || 'https://passports.io/api/country', allCountriesInfoUrl: ALL_COUNTRIES_INFO_URL || 'https://passports.io/api/countries', - bankAccountsInstance: - BANKACCOUNTS_KYCC_INSTANCE || 'https://dev.instance.kyc-chain.com/api/v2/', bankAccountsPriceOverride: BANKACCOUNTS_PRICE_OVERRIDE, bankAccountsTemplateOverride: BANKACCOUNTS_TEMPLATE_OVERRIDE, bankAccountsApiUrl: BANKACCOUNTS_API_URL || 'https://api.bankaccounts.io/api/bank-accounts', @@ -129,9 +127,6 @@ const dev = { kycApiEndpoint: 'https://token-sale-demo-api.kyc-chain.com/', chainId: 3, node: 'infura', - incorporationsInstance: - INCORPORATION_KYCC_INSTANCE || 'https://dev.instance.kyc-chain.com/api/v2/', - constants: { primaryToken: PRIMARY_TOKEN || 'KI' }, @@ -154,8 +149,6 @@ const prod = { kycApiEndpoint: 'https://tokensale-api.selfkey.org/', chainId: 1, node: 'infura', - incorporationsInstance: - INCORPORATION_KYCC_INSTANCE || 'https://flagtheory-v2.instance.kyc-chain.com/api/v2/', constants: { primaryToken: PRIMARY_TOKEN || 'KEY' }, diff --git a/src/common/kyc/index.js b/src/common/kyc/index.js index 6df4b0370..dcf3ab4d9 100644 --- a/src/common/kyc/index.js +++ b/src/common/kyc/index.js @@ -45,15 +45,15 @@ export const kycTypes = { KYC_APPLICATIONS_RESET: 'kyc/applications/reset' }; -const incorporationsRPDetails = { - name: 'Incorporations', - status: 'active', - description: 'Incorporations', - relying_party_config: { - rootEndpoint: config.incorporationsInstance, +const devRPDetails = { + name: 'Dev', + status: config.kyccUrlOverride ? 'active' : 'inactive', + description: 'Dev', + relyingPartyConfig: { + rootEndpoint: config.kyccUrlOverride, did: true, endpoints: { - '/templates/:id': `${config.incorporationsInstance}templates/:id?format=minimum` + '/templates/:id': `${config.kyccUrlOverride}templates/:id?format=minimum` } } }; @@ -72,14 +72,13 @@ export const kycSelectors = { if (rp && !rp.disabled) { return true; } - let service; - if (rpName === 'incorporations') { - service = { ...incorporationsRPDetails }; - } else { - service = marketplaceSelectors.selectRPDetails(state, rpName); + let service = marketplaceSelectors.selectRPDetails(state, rpName); + + if (devRPDetails.status === 'active') { + service = { ...devRPDetails }; } - const rpConfig = service.relying_party_config || service.relyingPartyConfig; + const rpConfig = service.relyingPartyConfig; return service.status === 'active' && rpConfig; }, relyingPartyShouldUpdateSelector(state, rpName, authenticate = true) { @@ -316,20 +315,23 @@ const loadRelyingPartyOperation = ( afterAuthRoute, cancelRoute ) => async (dispatch, getState) => { - const walletType = appSelectors.selectApp(getState()).walletType; + const state = getState(); + const walletType = appSelectors.selectApp(state).walletType; if (!rpName) return null; - const wallet = walletSelectors.getWallet(getState()); + const wallet = walletSelectors.getWallet(state); if (!wallet) return; const ts = Date.now(); - let rp; - if (rpName === 'incorporations') { - rp = { ...incorporationsRPDetails }; - } else { - rp = marketplaceSelectors.selectRPDetails(getState(), rpName); + + let rp = marketplaceSelectors.selectRPDetails(state, rpName); + + if (devRPDetails.status === 'active') { + console.log('Selecting dev RP'); + rp = { ...devRPDetails }; } - const config = rp.relying_party_config || rp.relyingPartyConfig; + + const config = rp.relyingPartyConfig; try { await dispatch(kycActions.setCancelRoute(cancelRoute)); diff --git a/src/renderer/selfkey-id/main/components/selfkey-id-applications.jsx b/src/renderer/selfkey-id/main/components/selfkey-id-applications.jsx index 3fbf0e6b9..4c8ff3f03 100644 --- a/src/renderer/selfkey-id/main/components/selfkey-id-applications.jsx +++ b/src/renderer/selfkey-id/main/components/selfkey-id-applications.jsx @@ -310,8 +310,7 @@ class SelfkeyIdApplicationsComponent extends Component { } const getRpInfo = (rpName, field) => { - // return config.relyingPartyInfo[rpName][field]; - return config.relyingPartyInfo['incorporations'][field]; + return config.relyingPartyInfo[rpName][field]; }; const getRpName = title => { From 0df072d1c7a26d2d1dd9231a41278cff54f8a621 Mon Sep 17 00:00:00 2001 From: Andre Goncalves Date: Tue, 17 Sep 2019 11:00:00 +0100 Subject: [PATCH 124/207] fix: remove optional routing params --- src/renderer/marketplace/incorporation/index.jsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/renderer/marketplace/incorporation/index.jsx b/src/renderer/marketplace/incorporation/index.jsx index 3113d25df..53d53beb8 100644 --- a/src/renderer/marketplace/incorporation/index.jsx +++ b/src/renderer/marketplace/incorporation/index.jsx @@ -24,15 +24,15 @@ class MarketplaceIncorporationComponent extends Component { component={IncorporationsDetailsContainer} />
From be06d2278ea39ce1b13678e559f91c8c826cbda8 Mon Sep 17 00:00:00 2001 From: Andre Goncalves Date: Tue, 17 Sep 2019 11:17:49 +0100 Subject: [PATCH 125/207] fix: incorporations pricing and active selector --- src/main/marketplace/inventory/inventory-service.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/marketplace/inventory/inventory-service.js b/src/main/marketplace/inventory/inventory-service.js index 4aa1303c0..745f78352 100644 --- a/src/main/marketplace/inventory/inventory-service.js +++ b/src/main/marketplace/inventory/inventory-service.js @@ -152,8 +152,11 @@ export class FlagtheoryIncorporationsInventoryFetcher extends InventoryFetcher { return { sku, name, - status: data.templateId ? 'active' : 'inactive', - price: data.walletPrice || null, + status: data.templateId && data.showInWallet ? 'active' : 'inactive', + price: + data.activeTestPrice && data.testPrice + ? data.testPrice + : data.walletPrice || null, priceCurrency: 'USD', category: 'incorporations', vendorId: 'flagtheory_incorporations', From d3496e74555ed4b4c884e6680cf5dcf1eaf8c11a Mon Sep 17 00:00:00 2001 From: designhorf Date: Tue, 17 Sep 2019 15:31:36 +0200 Subject: [PATCH 126/207] feat: added Click Away Listener to handle dropdown --- .../wallet/main/toolbar-container.jsx | 7 +++ src/renderer/wallet/main/toolbar.jsx | 53 ++++++++++++------- 2 files changed, 41 insertions(+), 19 deletions(-) diff --git a/src/renderer/wallet/main/toolbar-container.jsx b/src/renderer/wallet/main/toolbar-container.jsx index 141c05208..05e78902f 100644 --- a/src/renderer/wallet/main/toolbar-container.jsx +++ b/src/renderer/wallet/main/toolbar-container.jsx @@ -17,6 +17,12 @@ class ToolbarContainer extends Component { }); }; + closeProfile = isProfileOpen => { + this.setState({ + isProfileOpen: false + }); + }; + toggleProfile = isProfileOpen => { this.setState({ isProfileOpen @@ -50,6 +56,7 @@ class ToolbarContainer extends Component { onCreateCorporateProfileClick={this.createCorporateProfile} onToggleMenu={this.toggleDrawer} primaryToken={config.constants.primaryToken} + closeProfile={this.closeProfile} /> ); } diff --git a/src/renderer/wallet/main/toolbar.jsx b/src/renderer/wallet/main/toolbar.jsx index e00a7df64..fa64fb60c 100644 --- a/src/renderer/wallet/main/toolbar.jsx +++ b/src/renderer/wallet/main/toolbar.jsx @@ -1,5 +1,12 @@ import React, { Component } from 'react'; -import { createStyles, withStyles, Button, Grid, Typography } from '@material-ui/core'; +import { + createStyles, + withStyles, + Button, + Grid, + Typography, + ClickAwayListener +} from '@material-ui/core'; import { Link } from 'react-router-dom'; import { MenuNewIcon, @@ -198,26 +205,32 @@ const ProfileList = withStyles(profileStyle)( } ); -const Profile = withStyles(styles)(({ classes, profile, isOpen, onProfileClick }) => ( - - - {profile.type === 'individual' ? : } - - {profile.name || defaultIdentityName(profile)} - - {profile.type === 'individual' ? 'Personal Profile' : 'Corporate Profile'} - +const Profile = withStyles(styles)(({ classes, profile, isOpen, onProfileClick, closeProfile }) => ( + + + + + {profile.type === 'individual' ? : } + + + + {profile.name || defaultIdentityName(profile)} + + + {profile.type === 'individual' ? 'Personal Profile' : 'Corporate Profile'} + + + + + - - - - + )); class Toolbar extends Component { @@ -227,6 +240,7 @@ class Toolbar extends Component { onToggleMenu, isSidebarOpen, isProfileOpen, + closeProfile, selectedProfile, onProfileClick, onProfileSelect, @@ -278,6 +292,7 @@ class Toolbar extends Component { profile={selectedProfile} isOpen={isProfileOpen} onProfileClick={onProfileClick} + closeProfile={closeProfile} /> From ce9a4275aba58698ab2da2c127c380858d371167 Mon Sep 17 00:00:00 2001 From: Eduardo Santiago Moura Date: Wed, 18 Sep 2019 10:48:42 -0300 Subject: [PATCH 127/207] Update main-window.js --- src/main/main-window.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/main-window.js b/src/main/main-window.js index f0476024b..d56f9586c 100644 --- a/src/main/main-window.js +++ b/src/main/main-window.js @@ -51,7 +51,7 @@ export const createMainWindow = () => { mainWindow.loadURL(webAppPath); - // mainWindow.setMenu(null); // in order to don't show electron default menu bar + mainWindow.setMenu(null); // in order to don't show electron default menu bar if (isDebugMode()) { log.info('app is running in debug mode'); From e98f19da281113995dd5823949636c1d3d5831a8 Mon Sep 17 00:00:00 2001 From: Andre Goncalves Date: Thu, 19 Sep 2019 09:58:59 +0100 Subject: [PATCH 128/207] feat: add feature flag for corporate --- src/common/config.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/common/config.js b/src/common/config.js index e1f667e88..79f35e998 100644 --- a/src/common/config.js +++ b/src/common/config.js @@ -115,7 +115,8 @@ const common = { ], features: { paymentContract: false, - scheduler: false + scheduler: true, + corporate: false } }; @@ -135,7 +136,8 @@ const dev = { paymentSplitterAddress: '0xb91FF8627f30494d27b91Aac1cB3c7465BE58fF5', features: { paymentContract: false, - scheduler: true + scheduler: true, + corporate: true }, testWalletAddress: '0x23d233933c86f93b74705cf0d236b39f474249f8', testDidAddress: '0xee10a3335f48e10b444e299cf017d57879109c1e32cec3e31103ceca7718d0ec' @@ -157,7 +159,8 @@ const prod = { paymentSplitterAddress: '0xC3f1fbe8f4BE283426F913f0F2BE8329fC6BE041', features: { paymentContract: false, - scheduler: true + scheduler: true, + corporate: false } }; From 7b8378c224e0f0a2d37682986fd611a6c42174bb Mon Sep 17 00:00:00 2001 From: Andre Goncalves Date: Thu, 19 Sep 2019 12:04:20 +0100 Subject: [PATCH 129/207] feat: wip information table --- .../common/corporate-information.jsx | 128 ++++++++++++++++++ stories/corporate.stories.js | 6 +- 2 files changed, 132 insertions(+), 2 deletions(-) create mode 100644 src/renderer/corporate/common/corporate-information.jsx diff --git a/src/renderer/corporate/common/corporate-information.jsx b/src/renderer/corporate/common/corporate-information.jsx new file mode 100644 index 000000000..31975bf7d --- /dev/null +++ b/src/renderer/corporate/common/corporate-information.jsx @@ -0,0 +1,128 @@ +import React from 'react'; +import { + Grid, + CardHeader, + Card, + CardContent, + Typography, + Table, + TableHead, + TableBody, + TableRow, + TableCell +} from '@material-ui/core'; +import { IdCardIcon, SmallTableHeadRow, SmallTableRow, SmallTableCell } from 'selfkey-ui'; +import { withStyles } from '@material-ui/core'; + +const styles = theme => ({ + hr: { + backgroundColor: '#303C49', + border: 'none', + boxSizing: 'border-box', + height: '1px', + margin: '5px 16px' + }, + card: {}, + cardHeader: { + whiteSpace: 'normal', + wordBreak: 'break-all' + }, + regularText: { + '& span': { + fontWeight: 400 + } + }, + attr: { + margin: '0.5em', + display: 'block', + '& .label': { + display: 'inline-block', + minWidth: '12em' + }, + '& h5': { + display: 'inline-block' + }, + '& svg': { + marginRight: '0.5em', + verticalAlign: 'middle' + } + } +}); + +const CorporateInformation = withStyles(styles)(props => { + const { classes } = props; + return ( + + + + +
+ + + + + + + + + + Information provided here will be used for the KYC + processes in the Marketplace. + + + + + + + + + + Information + + + + + Label + + + + + Last edited + + + + + Actions + + + + + +
+
+
+
+
+
+
+
+ ); +}); + +export { CorporateInformation }; +export default CorporateInformation; diff --git a/stories/corporate.stories.js b/stories/corporate.stories.js index 36d920ef0..53b639b4b 100644 --- a/stories/corporate.stories.js +++ b/stories/corporate.stories.js @@ -10,6 +10,7 @@ import { CorporateApplicationsSummary } from '../src/renderer/corporate/common/c import { CorporateCapTable } from '../src/renderer/corporate/common/corporate-cap-table'; import { CorporateShareholding } from '../src/renderer/corporate/common/corporate-shareholding'; import { CorporateOrgChart } from '../src/renderer/corporate/common/corporate-org-chart'; +import { CorporateInformation } from '../src/renderer/corporate/common/corporate-information'; import { CorporateWizard } from '../src/renderer/corporate/wizard/corporate-wizard'; import { CorporateAddMember } from '../src/renderer/corporate/member/corporate-add-member'; @@ -56,7 +57,7 @@ storiesOf('Corporate/Dashboard Tabs', module) /> )); -storiesOf('Corporate/Blocks', module) +storiesOf('Corporate/Components', module) .add('Company', () => ( ) .add('Corporate Org Chart', () => ( - )); + )) + .add('Corporate Informations', () => ); storiesOf('Corporate', module).add('Wizard', () => ); From 30cbb83906ba50fdbad7a9e0ba94ac35f2bc8b0a Mon Sep 17 00:00:00 2001 From: Maxim Kovalov Date: Thu, 19 Sep 2019 17:33:48 +0300 Subject: [PATCH 130/207] feat(dev-attributes): different attr source on dev --- src/common/identity/utils.js | 63 +++++++++++++++++++ src/main/identity/document.js | 10 +-- src/main/identity/id-attribute-schema.js | 40 ------------ src/main/identity/id-attribute-schema.spec.js | 33 ---------- src/main/identity/id-attribute-type.js | 34 +++++----- src/main/identity/id-attribute.js | 11 +++- src/main/identity/repository.js | 20 +++--- src/main/identity/ui-schema.js | 19 +++--- .../20190919165010_attr-type-env.js | 38 +++++++++++ 9 files changed, 150 insertions(+), 118 deletions(-) delete mode 100644 src/main/identity/id-attribute-schema.js delete mode 100644 src/main/identity/id-attribute-schema.spec.js create mode 100644 src/main/migrations/20190919165010_attr-type-env.js diff --git a/src/common/identity/utils.js b/src/common/identity/utils.js index 95a44959d..ab7e5d26a 100644 --- a/src/common/identity/utils.js +++ b/src/common/identity/utils.js @@ -1,5 +1,8 @@ import Ajv from 'ajv'; +import RefParser from 'json-schema-ref-parser'; import { Logger } from 'common/logger'; +import { sleep } from '../utils/async'; +import fetch from 'node-fetch'; const log = new Logger('identity-utils'); @@ -222,4 +225,64 @@ jsonSchema.removeMeta = (schema, maxDepth = 10) => { return schema; }; +jsonSchema.loadRemoteSchema = async (url, options, attempt = 1) => { + if (options.env === 'development') { + url = url.replace('/schema/', '/dev-schema/'); + } + try { + let res = await fetch(url); + if (res.status >= 400) { + throw new Error('Failed to fetch schema from remote'); + } + return await res.json(); + } catch (error) { + log.error('Load schema %s attempt %d error, %s', url, attempt, error); + if (attempt <= 3) { + await sleep(attempt * 200); + return jsonSchema.loadRemoteSchema(url, options, attempt + 1); + } + throw error; + } +}; + +jsonSchema.dereference = (schema, options) => { + const resolver = { + order: 1, + canRead: /^platform\.selfkey\.org:/i, + async read(file) { + return jsonSchema.loadRemoteSchema(file, options); + } + }; + return RefParser.dereference(schema, { resolve: { selfkey: resolver } }); +}; + +jsonSchema.getDefaultRepo = (schema, options) => { + if (!schema.identityAttributeRepository) { + return null; + } + return options.env === 'development' + ? schema.identityAttributeRepository.replace('/repository.json', '/dev-repository.json') + : schema.identityAttributeRepository; +}; + +jsonSchema.loadRemoteRepository = async (url, options, attempt = 1) => { + if (options.env === 'development') { + url = url.replace('/repository.json', '/dev-repository.json'); + } + try { + let res = await fetch(url); + if (res.status >= 400) { + throw new Error('Failed to fetch repository from remote'); + } + return await res.json(); + } catch (error) { + log.error('Load repository %s attempt %d error, %s', url, attempt, error); + if (attempt <= 3) { + await sleep(attempt * 200); + return jsonSchema.loadRemoteRepository(url, options, attempt + 1); + } + throw error; + } +}; + export default { identityAttributes, jsonSchema }; diff --git a/src/main/identity/document.js b/src/main/identity/document.js index dfda05e3f..ce7b939f0 100644 --- a/src/main/identity/document.js +++ b/src/main/identity/document.js @@ -1,8 +1,9 @@ import { Model } from 'objection'; import BaseModel from '../common/base-model'; +import { isDevMode } from 'common/utils/common'; import { formatDataUrl } from 'common/utils/document'; const TABLE_NAME = 'documents'; - +const env = isDevMode() ? 'development' : 'production'; export class Document extends BaseModel { static tableName = TABLE_NAME; static idColumn = 'id'; @@ -14,7 +15,8 @@ export class Document extends BaseModel { mimeType: { type: 'string' }, size: { type: 'integer' }, buffer: { type: 'binary' }, - attributeId: { type: 'integer' } + attributeId: { type: 'integer' }, + env: { type: 'string', enum: ['production', 'development'], default: env } }, required: ['attributeId', 'mimeType', 'size', 'buffer'] }; @@ -37,7 +39,7 @@ export class Document extends BaseModel { return this.query() .select(`${TABLE_NAME}.*`) .join('id_attributes', `${TABLE_NAME}.attributeId`, 'id_attributes.id') - .where({ 'id_attributes.identityId': identityId }); + .where({ 'id_attributes.identityId': identityId, [`${TABLE_NAME}.env`]: env }); } static findAllByAttributeId(attributeId) { @@ -53,7 +55,7 @@ export class Document extends BaseModel { } static create(itm, tx) { - return this.query(tx).insertAndFetch(itm); + return this.query(tx).insertAndFetch({ ...itm, env }); } static delete(id, tx) { diff --git a/src/main/identity/id-attribute-schema.js b/src/main/identity/id-attribute-schema.js deleted file mode 100644 index 7f2a6444c..000000000 --- a/src/main/identity/id-attribute-schema.js +++ /dev/null @@ -1,40 +0,0 @@ -import { Model } from 'objection'; -import BaseModel from '../common/base-model'; - -const TABLE_NAME = 'id_attribute_schemas'; - -export class IdAttributeSchema extends BaseModel { - static tableName = TABLE_NAME; - static idColumn = 'type'; - static jsonSchema = { - type: 'object', - required: ['type'], - properties: { - type: { type: 'string' }, - expires: { type: 'integer' }, - jsonSchema: { type: 'object' }, - uiSchema: { type: 'object' }, - jsonSchemaUrl: { type: 'string' }, - uiSchemaUrl: { type: 'string' } - } - }; - static get relationMappings() { - const IdAttributeType = require('./id-attribute-type').default; - return { - attributeType: { - relation: Model.BelongsToOneRelation, - modelClass: IdAttributeType, - join: { - from: `${this.tableName}.type`, - to: `${IdAttributeType.tableName}.key` - } - } - }; - } - - hasExpired() { - return Date.now() > this.expires; - } -} - -export default IdAttributeSchema; diff --git a/src/main/identity/id-attribute-schema.spec.js b/src/main/identity/id-attribute-schema.spec.js deleted file mode 100644 index 9143a67eb..000000000 --- a/src/main/identity/id-attribute-schema.spec.js +++ /dev/null @@ -1,33 +0,0 @@ -import IdAttributeSchema from './id-attribute-schema'; -import TestDb from '../db/test-db'; - -describe('IdAttributeSchema', () => { - beforeEach(async () => { - await TestDb.init(); - }); - - afterEach(async () => { - await TestDb.reset(); - }); - - afterAll(async () => { - await TestDb.destroy(); - }); - it('sanity', async () => { - let schema = { - type: 'first_name', - jsonSchema: { test: 'json' }, - uiSchema: { test: 'ui' }, - expires: 1234 - }; - let schemas = await IdAttributeSchema.query(); - expect(schemas.length).toBe(0); - let schemaId = await IdAttributeSchema.query().insert(schema); - let createdSchema = await IdAttributeSchema.query() - .findById(schemaId.$id()) - .debug(); - expect(createdSchema).toMatchObject(schema); - schemas = await IdAttributeSchema.query(); - expect(schemas.length).toBe(1); - }); -}); diff --git a/src/main/identity/id-attribute-type.js b/src/main/identity/id-attribute-type.js index b533a4ba1..7c9b9b3a8 100644 --- a/src/main/identity/id-attribute-type.js +++ b/src/main/identity/id-attribute-type.js @@ -1,14 +1,14 @@ import { Model, transaction } from 'objection'; import BaseModel from '../common/base-model'; -import RefParser from 'json-schema-ref-parser'; -import fetch from 'node-fetch'; +import { isDevMode } from 'common/utils/common'; +import { jsonSchema } from 'common/identity/utils'; import { Logger } from 'common/logger'; - +const env = isDevMode() ? 'development' : 'production'; const log = new Logger('id-attribute-type-model'); const TABLE_NAME = 'id_attribute_types'; -const ID_ATTROBUTE_TYPE_EXPIRES = 86400000; // 1 day +const ID_ATTRIBUTE_TYPE_EXPIRES = 86400000; // 1 day export class IdAttributeType extends BaseModel { static get tableName() { @@ -28,7 +28,8 @@ export class IdAttributeType extends BaseModel { url: { type: 'string' }, defaultRepositoryId: { type: 'integer' }, content: { type: 'object' }, - expires: { type: 'integer' } + expires: { type: 'integer' }, + env: { type: 'string', enum: ['production', 'development'], default: env } } }; } @@ -79,7 +80,7 @@ export class IdAttributeType extends BaseModel { } static create(data, tx) { - return this.query(tx).insertAndFetch(data); + return this.query(tx).insertAndFetch({ ...data, env }); } static findById(id, tx) { @@ -87,32 +88,29 @@ export class IdAttributeType extends BaseModel { } static findAll(tx) { - return this.query(tx); + return this.query(tx).where({ env }); } static findByUrl(url, tx) { - return this.query(tx).findOne({ url }); + return this.query(tx).findOne({ url, env }); } static async loadRemote(url) { const Repository = require('./repository').default; let defaultRepo = null; - let res = await fetch(url); - if (res.status >= 400) { - throw new Error('Failed to fetch repository from remote'); - } - let remote = await res.json(); - remote = await RefParser.dereference(remote); - if (remote.identityAttributeRepository) { - defaultRepo = await Repository.findByUrl(remote.identityAttributeRepository); + let remote = await jsonSchema.loadRemoteSchema(url, { env }); + remote = await jsonSchema.dereference(remote, { env }); + let repoUrl = jsonSchema.getDefaultRepo(remote, { env }); + if (repoUrl) { + defaultRepo = await Repository.findByUrl(repoUrl); if (!defaultRepo) { - defaultRepo = await Repository.addRemoteRepo(remote.identityAttributeRepository); + defaultRepo = await Repository.addRemoteRepo(repoUrl); } } let remoteAttrType = { url, content: remote, - expires: Date.now() + (remote.expires || ID_ATTROBUTE_TYPE_EXPIRES) + expires: Date.now() + (remote.expires || ID_ATTRIBUTE_TYPE_EXPIRES) }; if (defaultRepo) remoteAttrType.defaultRepositoryId = defaultRepo.id; return remoteAttrType; diff --git a/src/main/identity/id-attribute.js b/src/main/identity/id-attribute.js index 94ca7cd63..eb111d372 100644 --- a/src/main/identity/id-attribute.js +++ b/src/main/identity/id-attribute.js @@ -2,7 +2,9 @@ import { Model, transaction } from 'objection'; import _ from 'lodash'; import BaseModel from '../common/base-model'; import Document from './document'; +import { isDevMode } from 'common/utils/common'; +const env = isDevMode() ? 'development' : 'production'; const TABLE_NAME = 'id_attributes'; export class IdAttribute extends BaseModel { @@ -23,7 +25,8 @@ export class IdAttribute extends BaseModel { name: { type: 'string' }, identityId: { type: 'integer' }, typeId: { type: 'integer' }, - data: { type: 'object' } + data: { type: 'object' }, + env: { type: 'string', enum: ['production', 'development'], default: env } } }; } @@ -64,7 +67,9 @@ export class IdAttribute extends BaseModel { const tx = await transaction.start(this.knex()); attr = { ...attr }; try { - let newAttr = await this.query(tx).insertAndFetch(_.omit(attr, ['documents'])); + let newAttr = await this.query(tx).insertAndFetch( + _.omit({ ...attr, env }, ['documents']) + ); attr.id = newAttr.id; attr = await this.update(attr, tx); await tx.commit(); @@ -124,7 +129,7 @@ export class IdAttribute extends BaseModel { return this.query() .select(`${TABLE_NAME}.*`) .join('id_attribute_types', `${TABLE_NAME}.typeId`, 'id_attribute_types.id') - .where({ identityId }) + .where({ identityId, [`${TABLE_NAME}.env`]: env }) .whereIn('id_attribute_types.url', urls); } } diff --git a/src/main/identity/repository.js b/src/main/identity/repository.js index 9c3b4b928..c8a62910d 100644 --- a/src/main/identity/repository.js +++ b/src/main/identity/repository.js @@ -1,10 +1,13 @@ import { Model, transaction } from 'objection'; import BaseModel from '../common/base-model'; -import fetch from 'node-fetch'; +import { jsonSchema } from 'common/identity/utils'; +import { isDevMode } from 'common/utils/common'; import IdAttributeType from './id-attribute-type'; import { Logger } from 'common/logger'; import { UiSchema } from './ui-schema'; +const env = isDevMode() ? 'development' : 'production'; + const log = new Logger('repository-model'); const TABLE_NAME = 'repository'; @@ -21,7 +24,8 @@ export class Repository extends BaseModel { name: { type: 'string' }, eager: { type: 'boolean', default: false }, content: { type: 'object' }, - expires: { type: 'integer' } + expires: { type: 'integer' }, + env: { type: 'string', enum: ['production', 'development'], default: env } } }; @@ -58,11 +62,11 @@ export class Repository extends BaseModel { } static findByUrl(url, tx) { - return this.query(tx).findOne({ url }); + return this.query(tx).findOne({ url, env }); } static create(itm, tx) { - return this.query(tx).insertAndFetch(itm); + return this.query(tx).insertAndFetch({ ...itm, env }); } static delete(id, tx) { @@ -70,15 +74,11 @@ export class Repository extends BaseModel { } static findAll(where) { - return this.query().where(where || {}); + return this.query().where({ ...where, env } || { env }); } static async loadRemote(url) { - let res = await fetch(url); - if (res.status >= 400) { - throw new Error('Failed to fetch repository from remote'); - } - let remoteRepo = await res.json(); + let remoteRepo = await jsonSchema.loadRemoteRepository(url, { env }); return { url, name: remoteRepo.name, diff --git a/src/main/identity/ui-schema.js b/src/main/identity/ui-schema.js index b1b4bb8a5..dde80bf6b 100644 --- a/src/main/identity/ui-schema.js +++ b/src/main/identity/ui-schema.js @@ -1,8 +1,10 @@ import { Model, transaction } from 'objection'; import BaseModel from '../common/base-model'; -import fetch from 'node-fetch'; +import { jsonSchema } from 'common/identity/utils'; +import { isDevMode } from 'common/utils/common'; import { Logger } from 'common/logger'; +const env = isDevMode() ? 'development' : 'production'; const log = new Logger('ui-schema-model'); const UI_SCHEMA_EXPIRES = 86400000; // 1 day @@ -21,7 +23,8 @@ export class UiSchema extends BaseModel { repositoryId: { type: 'integer' }, attributeTypeId: { type: 'integer' }, content: { type: 'object' }, - expires: { type: 'integer' } + expires: { type: 'integer' }, + env: { type: 'string', enum: ['production', 'development'], default: env } } }; @@ -49,11 +52,11 @@ export class UiSchema extends BaseModel { } static findAll(where) { - return this.query().where(where || {}); + return this.query().where({ ...where, env } || { env }); } static findByUrl(url, repositoryId, tx) { - return this.query(tx).findOne({ url, repositoryId }); + return this.query(tx).findOne({ url, repositoryId, env }); } static async findById(id, tx) { @@ -61,7 +64,7 @@ export class UiSchema extends BaseModel { } static create(itm, tx) { - return this.query(tx).insertAndFetch(itm); + return this.query(tx).insertAndFetch({ ...itm, env }); } static delete(id, tx) { @@ -69,11 +72,7 @@ export class UiSchema extends BaseModel { } static async loadRemote(url) { - let res = await fetch(url); - if (res.status >= 400) { - throw new Error('Failed to fetch ui-schema from remote'); - } - let remote = await res.json(); + const remote = await jsonSchema.loadRemoteSchema(url, { env }); let remoteSchema = { url, diff --git a/src/main/migrations/20190919165010_attr-type-env.js b/src/main/migrations/20190919165010_attr-type-env.js new file mode 100644 index 000000000..df774aa73 --- /dev/null +++ b/src/main/migrations/20190919165010_attr-type-env.js @@ -0,0 +1,38 @@ +/* istanbul ignore file */ +exports.up = async (knex, Promise) => { + await knex.schema.table('documents', t => { + t.string('env'); + }); + await knex.schema.table('id_attribute_types', t => { + t.string('env'); + }); + await knex.schema.table('id_attributes', t => { + t.string('env'); + }); + await knex.schema.table('repository', t => { + t.string('env'); + }); + await knex.schema.table('ui_schema', t => { + t.string('env'); + }); + + await knex('documents').update({ env: 'production' }); + await knex('id_attribute_types').update({ env: 'production' }); + await knex('id_attributes').update({ env: 'production' }); + await knex('repository').update({ env: 'production' }); + await knex('ui_schema').update({ env: 'production' }); + + const now = Date.now(); + await knex('repository').insert({ + url: 'http://platform.selfkey.org/dev-repository.json', + name: 'Selfkey.org', + eager: true, + content: '{}', + expires: 0, + createdAt: now, + updatedAt: now, + env: 'development' + }); +}; + +exports.down = async (knex, Promise) => {}; From 63ebf8ff7ae76a43f41786f0ac6c5221cf190f0d Mon Sep 17 00:00:00 2001 From: Andre Goncalves Date: Mon, 23 Sep 2019 10:57:34 +0100 Subject: [PATCH 131/207] feat: stories for company attributes --- .../common/corporate-information.jsx | 53 +++++++++++-- stories/corporate-data.js | 78 +++++++++++++++++++ stories/corporate.stories.js | 14 +++- 3 files changed, 138 insertions(+), 7 deletions(-) diff --git a/src/renderer/corporate/common/corporate-information.jsx b/src/renderer/corporate/common/corporate-information.jsx index 31975bf7d..0c1f71e32 100644 --- a/src/renderer/corporate/common/corporate-information.jsx +++ b/src/renderer/corporate/common/corporate-information.jsx @@ -1,4 +1,5 @@ import React from 'react'; +import moment from 'moment'; import { Grid, CardHeader, @@ -8,10 +9,15 @@ import { Table, TableHead, TableBody, - TableRow, - TableCell + IconButton } from '@material-ui/core'; -import { IdCardIcon, SmallTableHeadRow, SmallTableRow, SmallTableCell } from 'selfkey-ui'; +import { + IdCardIcon, + SmallTableHeadRow, + SmallTableRow, + SmallTableCell, + EditTransparentIcon +} from 'selfkey-ui'; import { withStyles } from '@material-ui/core'; const styles = theme => ({ @@ -49,8 +55,16 @@ const styles = theme => ({ } }); +const renderLastUpdateDate = ({ updatedAt }) => moment(updatedAt).format('DD MMM YYYY, hh:mm a'); + +// const renderAttributeLabel = ({ name }) => name || 'No label provided'; + +const renderAttributeValue = ({ data }) => data.value || ''; + +const renderAttributeTitle = attr => attr.type.content.title || 'No title provided'; + const CorporateInformation = withStyles(styles)(props => { - const { classes } = props; + const { classes, attributes = [], onEditAttribute } = props; return ( @@ -112,7 +126,36 @@ const CorporateInformation = withStyles(styles)(props => { - + + {attributes.map(attr => ( + + + + {renderAttributeTitle(attr)} + + + + + {renderAttributeValue(attr)} + + + + + {renderLastUpdateDate(attr)} + + + + + { + onEditAttribute(attr); + }} + /> + + + + ))} + diff --git a/stories/corporate-data.js b/stories/corporate-data.js index 00a05640c..d3109ceb7 100644 --- a/stories/corporate-data.js +++ b/stories/corporate-data.js @@ -87,3 +87,81 @@ export const corporateCapTable = [ children: [] } ]; + +export const corporateAttributes = [ + { + createdAt: 1568107330518, + updatedAt: 1568282607094, + name: 'Company Name', + type: { + content: { + $id: 'http://platform.selfkey.org/schema/attribute/company-name.json', + title: 'Company Name', + entityType: ['corporate'] + } + }, + data: { + value: 'ACME Inc' + } + }, + { + createdAt: 1568107330518, + updatedAt: 1568282607094, + name: 'Entity Type', + type: { + content: { + $id: 'http://platform.selfkey.org/schema/attribute/legal-entity-type.json', + title: 'Entity Type', + entityType: ['corporate'] + } + }, + data: { + value: 'LLC' + } + }, + { + createdAt: 1568107330518, + updatedAt: 1568282607094, + name: 'Jurisdiction', + type: { + content: { + $id: 'http://platform.selfkey.org/schema/attribute/legal-jurisdiction.json', + title: 'Legal Jurisdiction', + entityType: ['corporate'] + } + }, + data: { + value: 'Singapore' + } + }, + { + createdAt: 1568107330518, + updatedAt: 1568282607094, + name: 'Incorporation Date', + type: { + content: { + $id: 'http://platform.selfkey.org/schema/attribute/incorporation-date.json', + title: 'Incorporation Date', + entityType: ['corporate'] + } + }, + data: { + value: '17/10/1980' + } + }, + { + createdAt: 1568107330518, + updatedAt: 1568282607094, + name: 'Address', + type: { + content: { + $id: 'http://platform.selfkey.org/schema/attribute/physical-address.json', + title: 'Address', + entityType: ['corporate'] + } + }, + data: { + value: '1, Infinite Loop, California USA' + } + } +]; diff --git a/stories/corporate.stories.js b/stories/corporate.stories.js index 53b639b4b..423b970a4 100644 --- a/stories/corporate.stories.js +++ b/stories/corporate.stories.js @@ -14,7 +14,12 @@ import { CorporateInformation } from '../src/renderer/corporate/common/corporate import { CorporateWizard } from '../src/renderer/corporate/wizard/corporate-wizard'; import { CorporateAddMember } from '../src/renderer/corporate/member/corporate-add-member'; -import { corporateApplications, corporateCapTable, dummyMembers } from './corporate-data'; +import { + corporateApplications, + corporateCapTable, + dummyMembers, + corporateAttributes +} from './corporate-data'; storiesOf('Corporate', module).add('Dashboard', () => (
@@ -86,7 +91,12 @@ storiesOf('Corporate/Components', module) .add('Corporate Org Chart', () => ( )) - .add('Corporate Informations', () => ); + .add('Corporate Informations', () => ( + + )); storiesOf('Corporate', module).add('Wizard', () => ); From c9b66c89aec9cb11a3f838e5710be3ec72c04578 Mon Sep 17 00:00:00 2001 From: designhorf Date: Mon, 23 Sep 2019 12:22:21 +0200 Subject: [PATCH 132/207] fix: alignment of dropdown --- src/renderer/wallet/main/toolbar.jsx | 47 ++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/src/renderer/wallet/main/toolbar.jsx b/src/renderer/wallet/main/toolbar.jsx index fa64fb60c..7bc54c7bd 100644 --- a/src/renderer/wallet/main/toolbar.jsx +++ b/src/renderer/wallet/main/toolbar.jsx @@ -82,11 +82,15 @@ const styles = theme => ({ width: '1px' }, profileContainer: { - width: '100%', + left: '-33px', position: 'fixed', right: '2%', top: '63px', - zIndex: '999' + width: '100%', + zIndex: '999', + '@media screen and (min-width: 1480px)': { + left: '-43px' + } }, openedProfile: { transform: 'scaleY(-1)', @@ -101,17 +105,17 @@ const styles = theme => ({ const profileStyle = theme => createStyles({ profile: { - minWidth: '198px', - maxWidth: '198px', + minWidth: '208px', + maxWidth: '208px', float: 'right', - padding: '20px 15px 8px 15px', borderRadius: '4px', backgroundColor: '#1E262E', border: 'solid 1px #303c49' }, profileFooter: { bottom: '7px', - marginTop: '10px' + marginTop: '10px', + padding: '0 15px' }, horizontalDivider: { height: '1px', @@ -125,21 +129,33 @@ const profileStyle = theme => justifyContent: 'center' }, profileCorporate: { - padding: '20px 0px 14px 6px', + padding: '20px 15px 14px', display: 'flex', flexDirection: 'row', alignItems: 'center', justifyContent: 'center' }, profileDetail: { - paddingBottom: '20px', - cursor: 'pointer' + cursor: 'pointer', + padding: '10px 15px 10px 15px', + width: '208px', + '&:hover': { + backgroundColor: '#313D49' + }, + '&:first-child': { + marginTop: '5px' + } }, profileName: { paddingLeft: '15px' }, button: { width: '189px' + }, + smallButton: { + fontSize: '10px', + letterSpacing: '0.4px', + width: '100%' } }); @@ -167,10 +183,10 @@ const ProfileList = withStyles(profileStyle)( )} - + {el.name || defaultIdentityName(el)} - + {`${el.type.charAt(0).toUpperCase() + el.type.slice(1)} Profile`} @@ -185,7 +201,7 @@ const ProfileList = withStyles(profileStyle)( From 9ffe3b58118060785aaca8bfb9e6b14bf3e076ae Mon Sep 17 00:00:00 2001 From: Maxim Kovalov Date: Mon, 23 Sep 2019 13:55:32 +0300 Subject: [PATCH 133/207] feat(corporate-wizard): basic company attributes WIP --- .../wizard/corporate-wizard-container.jsx | 81 +- .../corporate/wizard/corporate-wizard.jsx | 1069 ++++++++--------- 2 files changed, 541 insertions(+), 609 deletions(-) diff --git a/src/renderer/corporate/wizard/corporate-wizard-container.jsx b/src/renderer/corporate/wizard/corporate-wizard-container.jsx index 2ff18a9ab..f1a7697f9 100644 --- a/src/renderer/corporate/wizard/corporate-wizard-container.jsx +++ b/src/renderer/corporate/wizard/corporate-wizard-container.jsx @@ -29,6 +29,7 @@ class CorporateWizardContainerComponent extends Component { return ( @@ -36,49 +37,49 @@ class CorporateWizardContainerComponent extends Component { } } -const dummyMembers = [ - { - id: '1', - name: 'Giacomo Guilizzoni', - type: 'Person', - role: 'Director, Shareholder', - citizenship: 'Italy', - residency: 'Singapore', - shares: '45%' - }, - { - id: '2', - name: 'Marco Botton Ltd', - type: 'Corporate', - role: 'Shareholder', - citizenship: 'Hong Kong', - residency: 'Hong Kong', - shares: '9%' - }, - { - id: '3', - name: 'Big Things Ltd', - type: 'Corporate', - role: 'Shareholder', - citizenship: 'Hong Kong', - residency: 'Hong Kong', - shares: '41%' - }, - { - id: '4', - name: 'John Dafoe', - type: 'Person', - role: 'Director', - citizenship: 'France', - residency: 'France', - shares: '5%' - } -]; +// const dummyMembers = [ +// { +// id: '1', +// name: 'Giacomo Guilizzoni', +// type: 'Person', +// role: 'Director, Shareholder', +// citizenship: 'Italy', +// residency: 'Singapore', +// shares: '45%' +// }, +// { +// id: '2', +// name: 'Marco Botton Ltd', +// type: 'Corporate', +// role: 'Shareholder', +// citizenship: 'Hong Kong', +// residency: 'Hong Kong', +// shares: '9%' +// }, +// { +// id: '3', +// name: 'Big Things Ltd', +// type: 'Corporate', +// role: 'Shareholder', +// citizenship: 'Hong Kong', +// residency: 'Hong Kong', +// shares: '41%' +// }, +// { +// id: '4', +// name: 'John Dafoe', +// type: 'Person', +// role: 'Director', +// citizenship: 'France', +// residency: 'France', +// shares: '5%' +// } +// ]; const mapStateToProps = (state, props) => { return { - walletType: appSelectors.selectWalletType(state), - members: dummyMembers + walletType: appSelectors.selectWalletType(state) + // members: dummyMembers }; }; diff --git a/src/renderer/corporate/wizard/corporate-wizard.jsx b/src/renderer/corporate/wizard/corporate-wizard.jsx index 752a61bba..581aa6a21 100644 --- a/src/renderer/corporate/wizard/corporate-wizard.jsx +++ b/src/renderer/corporate/wizard/corporate-wizard.jsx @@ -2,9 +2,9 @@ import React, { Component } from 'react'; import { Grid, - // CardHeader, - // Card, - // CardContent, + CardHeader, + Card, + CardContent, // Table, // TableBody, // TableRow, @@ -13,15 +13,13 @@ import { // TableHead, Typography, Button, - // Input, - // MenuItem, - // Select, + Input, + MenuItem, + Select, withStyles } from '@material-ui/core'; -// import { KeyboardArrowDown } from '@material-ui/icons'; -// import { EditTransparentIcon, DeleteIcon, SmallTableHeadRow, KeyPicker } from 'selfkey-ui'; - -import backgroundImage from '../../../../static/assets/images/icons/icon-marketplace.png'; +import { KeyboardArrowDown } from '@material-ui/icons'; +import { /* EditTransparentIcon, DeleteIcon, SmallTableHeadRow, */ KeyPicker } from 'selfkey-ui'; const styles = theme => ({ hr: { @@ -32,10 +30,7 @@ const styles = theme => ({ margin: '5px 16px' }, card: { - backgroundColor: '#1E262E', - backgroundImage: `url(${backgroundImage})`, - backgroundPosition: '90% 50%', - backgroundRepeat: 'no-repeat' + overflow: 'visible' }, labelCell: { whiteSpace: 'normal', @@ -97,591 +92,527 @@ const styles = theme => ({ } }); -class CorporateWizardComponent extends Component { - render() { - const { classes } = this.props; - return ( - - - SelfKey Corporate Vault Setup - - {/* - - - - - - -
- +const CompanyInformation = withStyles(styles)(props => { + const { classes, errors = {}, onFieldChange = () => {} } = props; + return ( + + + + +
+ + + + +
+ - - - + + + - - + + Legal Jurisdiction + + + + - } - style={{ - width: - '100%' - }} - > - - - Choose... - - - {[ - 'Jurisdiction 1', - 'Jurisdiction 2', - 'Jurisdiction 3', - 'Jurisdiction 4', - 'Jurisdiction 5' - ].map( - item => ( - - { - item - } - - ) - )} - - - - - - - Legal - Entity - Name - - - - - - - - + Choose... + + {[ + 'Jurisdiction 1', + 'Jurisdiction 2', + 'Jurisdiction 3', + 'Jurisdiction 4', + 'Jurisdiction 5' + ].map(item => ( + - - - - Legal - Entity - Type - - - - - - - - - - Creation - Date - - - - div': { - width: - '200px !important' - } - }} - /> - - - - - - - - Contact - Email - - (optional) - - - - - - {this - .state - .errorEmail && ( - - { - 'Email provided is invalid' - } - - )} - - - - - - Tax - ID - - (optional) - - - - - - {this - .state - .errorEmail && ( - - { - 'Email provided is invalid' - } - - )} - - - - - + {item} + + ))} + - - - - -
-
-
-
-
-
- - - - - -
- - - - - - - - - - Name - - - - - Type - - - - - Role + + + + Legal Entity Name - - - - Citizenship / - Incorporation + + + + + + + + + + + Legal Entity Type - - - - Residency / Domicile + + + + + + + + + Creation Date - - - - Shares + + + div': { + width: + '200px !important' + } + }} + /> + + + + + + + + Contact Email + + (optional) + - - - - Actions + + + + {errors.email && ( + + { + 'Email provided is invalid' + } + + )} + + + + + + Tax ID + + (optional) + - - - - - {members && - members.map(entry => { - return ( - + + + {errors.email && ( + - - - {entry.name} - - - - {entry.type} - - - {entry.role} - - - { - entry.citizenship - } - - - { - entry.residency - } - - - - { - entry.shares - } - - - - - { - this.handleEditMember( - entry - ); - }} - /> - - { - this.handleDeleteMember( - entry - ); - }} - > - - - - - ); - })} - -
-
-
- - - + { + 'Email provided is invalid' + } + + )} + + +
+
- - +
+
+ + + + + ); +}); + +// const MembersList = withStyles(styles)(props => { +// const { classes, members } = props; +// return ( +// +// +// +// +//
+// +// +// +// +// +// +// +// +// Name +// +// +// Type +// +// +// Role +// +// +// +// Citizenship / Incorporation +// +// +// +// +// Residency / Domicile +// +// +// +// +// Shares +// +// +// +// +// Actions +// +// +// +// +// +// {members && +// members.map(entry => { +// return ( +// +// +// +// {entry.name} +// +// +// {entry.type} +// {entry.role} +// +// {entry.citizenship} +// +// {entry.residency} +// +// +// {entry.shares} +// +// +// +// +// { +// this.handleEditMember( +// entry +// ); +// }} +// /> +// +// { +// this.handleDeleteMember( +// entry +// ); +// }} +// > +// +// +// +// +// ); +// })} +// +//
+//
+//
+// +// +// +// +// +//
+//
+//
+//
+//
+// ); +// }); + +class CorporateWizardComponent extends Component { + render() { + const { classes } = this.props; + return ( + + + SelfKey Corporate Vault Setup + + + + + + + {/* */} - */} - - - - - + + + + + + + From c45783b3412bbe0be80f87814534e207ce8d4406 Mon Sep 17 00:00:00 2001 From: Maxim Kovalov Date: Mon, 23 Sep 2019 14:23:56 +0300 Subject: [PATCH 134/207] fix(hw-wallet): unlock hw wallet --- src/main/wallet/wallet-service.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/wallet/wallet-service.js b/src/main/wallet/wallet-service.js index 242b17d8f..2c1e6fe7c 100644 --- a/src/main/wallet/wallet-service.js +++ b/src/main/wallet/wallet-service.js @@ -161,7 +161,7 @@ export class WalletService { async unlockWalletWithPublicKey(publicKey, hwPath, profile) { let wallet = await Wallet.findByPublicKey(publicKey); - this.setDefaultAddress(publicKey); + this.web3Service.setDefaultAddress(publicKey); if (!wallet) { wallet = await Wallet.create({ From 781153bdb197fd32e90da953e3f2486f67fd1a75 Mon Sep 17 00:00:00 2001 From: Maxim Kovalov Date: Mon, 23 Sep 2019 15:28:00 +0300 Subject: [PATCH 135/207] feat(corporate-wizard): company information form WIP --- .../wizard/corporate-wizard-container.jsx | 75 +++++- .../corporate/wizard/corporate-wizard.jsx | 105 ++++---- stories/corporate-data.js | 250 ++++++++++++++++++ stories/corporate.stories.js | 31 ++- 4 files changed, 396 insertions(+), 65 deletions(-) diff --git a/src/renderer/corporate/wizard/corporate-wizard-container.jsx b/src/renderer/corporate/wizard/corporate-wizard-container.jsx index f1a7697f9..024e65774 100644 --- a/src/renderer/corporate/wizard/corporate-wizard-container.jsx +++ b/src/renderer/corporate/wizard/corporate-wizard-container.jsx @@ -1,4 +1,5 @@ import React, { Component } from 'react'; +import _ from 'lodash'; import { connect } from 'react-redux'; import { appSelectors } from 'common/app'; import { CorporateWizard } from './corporate-wizard'; @@ -7,29 +8,85 @@ import { identityOperations } from 'common/identity'; class CorporateWizardContainerComponent extends Component { state = { - error: '', - errorEmail: false, - nickName: '', - firstName: '', - lastName: '', - email: '', - isDisabled: true + errors: {}, + jurisdiction: null, + taxId: null, + entityType: null, + email: null, + entityName: null, + creationDate: null + }; + + handleFieldChange = name => evt => { + const errors = { ...this.state.errors }; + let value = evt; + + if (evt && evt.target) { + value = evt.target.value; + } + + if (name === 'email') { + errors.email = value && !this.isValidEmail(value) ? 'Invalid email' : null; + } + this.setState({ + errors, + [name]: value + }); }; handleContinueClick = evt => { evt && evt.preventDefault(); - this.props.dispatch(identityOperations.createCorporateProfileOperation()); + this.props.dispatch( + identityOperations.createCorporateProfileOperation( + _.pick( + this.state, + 'jurisdiction', + 'taxId', + 'entityType', + 'email', + 'entityName', + 'creationDate' + ) + ) + ); }; handleCancelClick = evt => { evt && evt.preventDefault(); this.props.dispatch(push('/main/dashboard')); }; + + isValidEmail = email => { + var re = /^(([^<>()[\].,;:\s@"]+(\.[^<>()[\].,;:\s@"]+)*)|(".+"))@(([^<>()[\].,;:\s@"]+\.)+[^<>()[\].,;:\s@"]{2,})$/i; + return email ? re.test(String(email).toLowerCase()) : true; + }; + + isDisabled() { + return ( + !this.state.jurisdiction || + !this.state.entityType || + !this.state.entityName || + !this.state.creationDate || + (this.state.email && !this.isValidEmail(this.state.email)) + ); + } + render() { + const companyForm = _.pick( + this.state, + 'errors', + 'jurisdiction', + 'taxId', + 'entityType', + 'email', + 'entityName', + 'creationDate' + ); return ( diff --git a/src/renderer/corporate/wizard/corporate-wizard.jsx b/src/renderer/corporate/wizard/corporate-wizard.jsx index 581aa6a21..a2ff2bd84 100644 --- a/src/renderer/corporate/wizard/corporate-wizard.jsx +++ b/src/renderer/corporate/wizard/corporate-wizard.jsx @@ -93,7 +93,19 @@ const styles = theme => ({ }); const CompanyInformation = withStyles(styles)(props => { - const { classes, errors = {}, onFieldChange = () => {} } = props; + const { + classes, + jurisdictions = [], + entityTypes = [], + errors = {}, + jurisdiction, + taxId, + entityType, + email, + entityName, + creationDate, + onFieldChange = () => {} + } = props; return ( @@ -176,10 +188,12 @@ const CompanyInformation = withStyles(styles)(props => { @@ -229,11 +239,12 @@ const CompanyInformation = withStyles(styles)(props => { @@ -262,9 +273,10 @@ const CompanyInformation = withStyles(styles)(props => { @@ -315,9 +323,10 @@ const CompanyInformation = withStyles(styles)(props => { { fullWidth type="email" error={errors.email} - required + value={email} onChange={onFieldChange( 'email' )} @@ -408,27 +417,15 @@ const CompanyInformation = withStyles(styles)(props => { - {errors.email && ( - - { - 'Email provided is invalid' - } - - )} diff --git a/stories/corporate-data.js b/stories/corporate-data.js index 00a05640c..770e5ced1 100644 --- a/stories/corporate-data.js +++ b/stories/corporate-data.js @@ -87,3 +87,253 @@ export const corporateCapTable = [ children: [] } ]; + +export const entityTypes = [ + 'Company Limited by Shares (LTD)', + 'Limited Liability Company (LLC)', + 'Trust (TST)', + 'Foundation (FND)', + 'Limited Partnership (LLP)', + 'Other' +]; + +export const legalJurisdictions = [ + 'Afghanistan', + 'Albania', + 'Algeria', + 'Andorra', + 'Angola', + 'Anguilla', + 'Antigua and Barbuda', + 'Argentina', + 'Armenia', + 'Aruba', + 'Australia', + 'Austria', + 'Azerbaijan', + 'Bahamas', + 'Bangladesh', + 'Bahrain', + 'Barbados', + 'Belarus', + 'Belgium', + 'Belize', + 'Benin', + 'Bermuda', + 'Bhutan', + 'Bolivia', + 'Bosnia and Herzegovina', + 'Botswana', + 'Brazil', + 'British Virgin Islands', + 'Brunei', + 'Bulgaria', + 'Burkina Faso', + 'Burundi', + 'Cambodia', + 'Cameroon', + 'Canada', + 'Cape Verde', + 'Cayman Islands', + 'Central African Republic', + 'Chile', + "China, People's Republic of Hong Kong", + "China, People's Republic of Macau", + 'Taiwan', + 'Colombia', + 'Congo, Democratic Republic of the', + 'Congo, Republic of the', + 'Cook Islands', + 'Costa Rica', + "Côte d'Ivoire", + 'Croatia', + 'Cuba', + 'Curaçao', + 'Cyprus', + 'Czech Republic', + 'Denmark', + 'Danish Realms - Faroe Islands', + 'Danish Realms - Greenland', + 'Djibouti', + 'Dominica', + 'Dominican Republic', + 'Ecuador', + 'Egypt', + 'El Salvador', + 'Eritrea', + 'Estonia', + 'Ethiopia', + 'Fiji', + 'Finland', + 'France', + 'Gabon', + 'Gambia', + 'Georgia', + 'Germany', + 'Ghana', + 'Gibraltar', + 'Greece', + 'Grenada', + 'Guatemala', + 'Guernsey, Channel Islands', + 'Guinea', + 'Guyana', + 'Haiti', + 'Honduras', + 'Hungary', + 'Iceland', + 'India', + 'Indonesia', + 'Iran', + 'Iraq', + 'Ireland', + 'Isle of Man', + 'Israel', + 'Italy', + 'Jamaica', + 'Japan', + 'Jersey, Channel Islands', + 'Jordan', + 'Kazakhstan', + 'Kenya', + 'Kiribati', + 'Kosovo', + 'Kuwait', + 'Kyrgyzstan', + 'Laos', + 'Latvia', + 'Lebanon', + 'Lesotho', + 'Liberia', + 'Liechtenstein', + 'Lithuania', + 'Luxembourg', + 'Macedonia', + 'Madagascar', + 'Malta', + 'Malawi', + 'Malaysia', + 'Maldives', + 'Mali', + 'Marshall Islands', + 'Mauritania', + 'Mauritius', + 'Mexico', + 'Micronesia, Federated States of', + 'Moldova', + 'Monaco', + 'Mongolia', + 'Montenegro', + 'Montserrat', + 'Morocco', + 'Mozambique', + 'Myanmar', + 'Namibia', + 'Nauru', + 'Nepal', + 'Netherlands', + 'Caribbean Netherlands - Bonaire', + 'Caribbean Netherlands - Sint Eustatius ', + 'Caribbean Netherlands - Saba ', + 'New Zealand', + 'Nicaragua', + 'Niger', + 'Nigeria', + 'Niue', + 'Norway', + 'Oman', + 'Pakistan', + 'Palau', + 'Palestinian territories', + 'Panama', + 'Papua New Guinea', + 'Paraguay', + 'Peru', + 'Philippines', + 'Poland', + 'Portugal', + 'Qatar', + 'Romania', + 'Russian Federation', + 'Rwanda', + 'Saint Kitts and Nevis', + 'Saint Lucia', + 'Saint Vincent and the Grenadines', + 'Samoa', + 'San Marino', + 'São Tomé and Príncipe', + 'Saudi Arabia', + 'Senegal', + 'Serbia', + 'Seychelles', + 'Sierra Leone', + 'Singapore', + 'Slovakia', + 'Slovenia', + 'Solomon Islands', + 'South Africa', + 'South Korea', + 'South Sudan', + 'Spain', + 'Sri Lanka', + 'Sint Maarten', + 'Sudan', + 'Suriname', + 'Swaziland', + 'Sweden', + 'Switzerland', + 'Tajikistan', + 'Tanzania', + 'Thailand', + 'Timor-Leste', + 'Tonga', + 'Togo', + 'Tunisia', + 'Turkey', + 'Turks and Caicos Islands', + 'Trinidad & Tobago', + 'Uganda', + 'Ukraine', + 'United Arab Emirates', + 'United Kingdom', + 'United States - Alabama', + 'United States - Alaska', + 'United States - Arizona', + 'United States - Arkansas', + 'United States - California', + 'United States - Colorado', + 'United States - Connecticut', + 'United States - Delaware', + 'United States - Florida', + 'United States - Georgia', + 'United States - Hawaii', + 'United States - Idaho', + 'United States - Illinois', + 'United States - Indiana', + 'United States - Iowa', + 'United States - Kansas', + 'United States - Kentucky', + 'United States - Louisiana', + 'United States - Maine', + 'United States - Maryland', + 'United States - Massachusetts', + 'United States - Michigan', + 'United States - Minnesota', + 'United States - Mississippi', + 'United States - Missouri', + 'United States - Montana', + 'United States - Nebraska', + 'United States - Nevada', + 'United States - New Hampshire', + 'United States - New Jersey', + 'United States - New Mexico', + 'United States - New York', + 'Uruguay', + 'Uzbekistan', + 'Vanuatu', + 'Venezuela', + 'Vietnam', + 'Yemen', + 'Zambia', + 'Zimbabwe' +]; diff --git a/stories/corporate.stories.js b/stories/corporate.stories.js index 36d920ef0..18608d9d3 100644 --- a/stories/corporate.stories.js +++ b/stories/corporate.stories.js @@ -13,7 +13,13 @@ import { CorporateOrgChart } from '../src/renderer/corporate/common/corporate-or import { CorporateWizard } from '../src/renderer/corporate/wizard/corporate-wizard'; import { CorporateAddMember } from '../src/renderer/corporate/member/corporate-add-member'; -import { corporateApplications, corporateCapTable, dummyMembers } from './corporate-data'; +import { + corporateApplications, + corporateCapTable, + dummyMembers, + entityTypes, + legalJurisdictions +} from './corporate-data'; storiesOf('Corporate', module).add('Dashboard', () => (
@@ -86,6 +92,27 @@ storiesOf('Corporate/Blocks', module) )); -storiesOf('Corporate', module).add('Wizard', () => ); +storiesOf('Corporate/Wizard', module) + .add('default', () => ( + action(`field change ${name}:`)} + /> + )) + .add('field error', () => ( + action(`field change ${name}:`)} + /> + )); storiesOf('Corporate', module).add('Add Member', () => ); From 7a51926525ed366d071a8569044dd7a530a8c89f Mon Sep 17 00:00:00 2001 From: designhorf Date: Mon, 23 Sep 2019 18:30:03 +0200 Subject: [PATCH 136/207] fix: width of switch profile dropdown --- src/renderer/wallet/main/toolbar.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/wallet/main/toolbar.jsx b/src/renderer/wallet/main/toolbar.jsx index 7bc54c7bd..426a9aa58 100644 --- a/src/renderer/wallet/main/toolbar.jsx +++ b/src/renderer/wallet/main/toolbar.jsx @@ -228,7 +228,7 @@ const ProfileList = withStyles(profileStyle)( const Profile = withStyles(styles)(({ classes, profile, isOpen, onProfileClick, closeProfile }) => ( - + {profile.type === 'individual' ? : } From 866501068bf63a051d78e25f26941108d6963b1a Mon Sep 17 00:00:00 2001 From: designhorf Date: Tue, 24 Sep 2019 08:02:02 +0200 Subject: [PATCH 137/207] feat: add title to all icons in Sidebar --- src/renderer/wallet/main/sidebar.jsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/renderer/wallet/main/sidebar.jsx b/src/renderer/wallet/main/sidebar.jsx index 131a73e78..b9c66e88f 100644 --- a/src/renderer/wallet/main/sidebar.jsx +++ b/src/renderer/wallet/main/sidebar.jsx @@ -247,7 +247,7 @@ class Sidebar extends Component { component={dashboard} key="dashboard" > - + @@ -260,7 +260,7 @@ class Sidebar extends Component { component={marketplace} key="marketplace" > - + - + - + @@ -377,7 +377,7 @@ class Sidebar extends Component { }} key="helpAndSupport" > - + @@ -401,7 +401,7 @@ class Sidebar extends Component { component={switchAccount} key="switchAccount" > - + @@ -409,7 +409,7 @@ class Sidebar extends Component { - + From c12950ade9049d8a67556133b5eb525a7744ec90 Mon Sep 17 00:00:00 2001 From: Andre Goncalves Date: Tue, 24 Sep 2019 10:13:48 +0100 Subject: [PATCH 138/207] feat: disabled new corp button if corp is disabled --- src/renderer/wallet/main/toolbar.jsx | 53 ++++++++++++++++------------ 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/src/renderer/wallet/main/toolbar.jsx b/src/renderer/wallet/main/toolbar.jsx index fa64fb60c..06298d70a 100644 --- a/src/renderer/wallet/main/toolbar.jsx +++ b/src/renderer/wallet/main/toolbar.jsx @@ -18,6 +18,7 @@ import { } from 'selfkey-ui'; import PriceBox from '../../price-box'; import Sidebar from './sidebar'; +import { featureIsEnabled } from 'common/feature-flags'; const styles = theme => ({ wrapper: { @@ -177,28 +178,36 @@ const ProfileList = withStyles(profileStyle)( ))} - -
- - {/* - - - - */} - - - - - + {featureIsEnabled('corporate') && ( + + +
+ + {/* + + + + */} + + + + + + + )}
) ); From cad37355da6f77076d6d2412760eebd92811c963 Mon Sep 17 00:00:00 2001 From: designhorf Date: Tue, 24 Sep 2019 11:38:08 +0200 Subject: [PATCH 139/207] fix: removed inline styles --- src/renderer/wallet/main/toolbar.jsx | 35 +++++++++++++++++++++------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/src/renderer/wallet/main/toolbar.jsx b/src/renderer/wallet/main/toolbar.jsx index 426a9aa58..6fb092366 100644 --- a/src/renderer/wallet/main/toolbar.jsx +++ b/src/renderer/wallet/main/toolbar.jsx @@ -99,6 +99,23 @@ const styles = theme => ({ closedProfile: { transform: 'scaleY(1)', '-webkit-transform': 'scaleY(1)' + }, + profileIcon: { + marginTop: '13px', + paddingRight: '15px' + }, + absolute: { + position: 'absolute' + }, + maxWidth: { + maxWidth: '240px' + }, + toolbarProfile: { + cursor: 'pointer', + width: '222px' + }, + priceBox: { + paddingRight: '10px' } }); @@ -147,7 +164,10 @@ const profileStyle = theme => } }, profileName: { - paddingLeft: '15px' + paddingLeft: '15px', + '& h6:first-child': { + marginBottom: '5px' + } }, button: { width: '189px' @@ -183,7 +203,7 @@ const ProfileList = withStyles(profileStyle)( )}
- + {el.name || defaultIdentityName(el)} @@ -242,7 +262,7 @@ const Profile = withStyles(styles)(({ classes, profile, isOpen, onProfileClick, - + onToggleMenu(!isSidebarOpen)} /> - + @@ -296,7 +315,7 @@ class Toolbar extends Component { - +
@@ -308,7 +327,7 @@ class Toolbar extends Component { alignItems="center" spacing={0} > - + Date: Tue, 24 Sep 2019 10:50:08 +0100 Subject: [PATCH 140/207] feat: corporate documents componenent --- .../corporate/common/corporate-documents.jsx | 235 ++++++++++++++++++ stories/corporate-data.js | 50 ++++ stories/corporate.stories.js | 12 +- 3 files changed, 296 insertions(+), 1 deletion(-) create mode 100644 src/renderer/corporate/common/corporate-documents.jsx diff --git a/src/renderer/corporate/common/corporate-documents.jsx b/src/renderer/corporate/common/corporate-documents.jsx new file mode 100644 index 000000000..de73d69e5 --- /dev/null +++ b/src/renderer/corporate/common/corporate-documents.jsx @@ -0,0 +1,235 @@ +import React from 'react'; +import moment from 'moment'; +import { + Grid, + CardHeader, + Card, + CardContent, + Typography, + Table, + TableCell, + TableRow, + TableHead, + TableBody, + IconButton, + Button +} from '@material-ui/core'; +import { + SmallTableHeadRow, + EditTransparentIcon, + DeleteIcon, + FilePdfIcon, + FileImageIcon, + FileDefaultIcon, + FileMultipleIcon, + FileAudioIcon +} from 'selfkey-ui'; +import { withStyles } from '@material-ui/core'; + +const styles = theme => ({ + hr: { + backgroundColor: '#303C49', + border: 'none', + boxSizing: 'border-box', + height: '1px', + margin: '5px 16px' + }, + card: {}, + cardHeader: { + whiteSpace: 'normal', + wordBreak: 'break-all' + }, + regularText: { + '& span': { + fontWeight: 400 + } + }, + attr: { + margin: '0.5em', + display: 'block', + '& .label': { + display: 'inline-block', + minWidth: '12em' + }, + '& h5': { + display: 'inline-block' + }, + '& svg': { + marginRight: '0.5em', + verticalAlign: 'middle' + } + }, + documentColumn: { + display: 'flex', + alignItems: 'center', + '& .file-icon': { + marginRight: '15px' + } + } +}); + +const renderLastUpdateDate = ({ updatedAt }) => moment(updatedAt).format('DD MMM YYYY, hh:mm a'); + +// const renderAttributeLabel = ({ name }) => name || 'No label provided'; + +// const renderAttributeValue = ({ data }) => data.value || ''; + +const renderAttributeTitle = attr => attr.type.content.title || 'No title provided'; + +const renderDocumentName = ({ entry, classes }) => { + let fileType = null; + let fileName = null; + let FileIcon = FileDefaultIcon; + + if (entry.documents.length === 1) { + fileName = entry.documents[0].name; + fileType = entry.documents[0].mimeType; + if (fileType) { + if (fileType === 'application/pdf') FileIcon = FilePdfIcon; + else if (fileType.startsWith('audio')) FileIcon = FileAudioIcon; + else if (fileType.startsWith('image')) FileIcon = FileImageIcon; + } + } else if (entry.documents.length > 1) { + fileName = `${entry.documents.length} files`; + FileIcon = FileMultipleIcon; + } + + return ( +
+
+ +
+
+ {entry.name} + + {fileName} + +
+
+ ); +}; + +const DocumentExpiryDate = ({ doc }) => { + let date; + if (!doc || !doc.data || !doc.data.value || !doc.data.value.expires) { + date = '-'; + } else { + date = moment(doc.data.value.expires).format('DD MMM YYYY'); + } + return {date}; +}; + +const CorporateDocuments = withStyles(styles)(props => { + const { classes, documents = [], onEditDocument, onDeleteDocument, onAddDocument } = props; + return ( + + + + +
+ + + + + + + + + Type + + + + Label + + + + + Expiry Date + + + + + Last Edited + + + + + Actions + + + + + + {documents.map(entry => ( + + + + {renderAttributeTitle(entry)} + + + + {renderDocumentName({ entry, classes })} + + + + + + + {renderLastUpdateDate(entry)} + + + + onEditDocument(entry)} + > + + + onDeleteDocument(entry)} + > + + + + + ))} + +
+
+
+ + + + + +
+
+
+
+
+ ); +}); + +export { CorporateDocuments }; +export default CorporateDocuments; diff --git a/stories/corporate-data.js b/stories/corporate-data.js index d3109ceb7..8cae9fa9c 100644 --- a/stories/corporate-data.js +++ b/stories/corporate-data.js @@ -165,3 +165,53 @@ export const corporateAttributes = [ } } ]; + +export const corporateDocuments = [ + { + createdAt: 1568107330518, + updatedAt: 1568282607094, + name: 'Certificate of Incorporation', + type: { + content: { + $id: + 'http://platform.selfkey.org/schema/attribute/certificate-of-incorporation.json', + title: 'Certificate of Incorporation', + entityType: ['corporate'] + } + }, + documents: [ + { + name: 'certificate.pdf', + mimeType: 'application/pdf' + } + ], + data: { + value: { + expires: 1568282607094 + } + } + }, + { + createdAt: 1568107330518, + updatedAt: 1568282607094, + name: 'Member Register', + type: { + content: { + $id: 'http://platform.selfkey.org/schema/attribute/member-register.json', + title: 'Member Register', + entityType: ['corporate'] + } + }, + documents: [ + { + name: 'member_register.doc', + mimeType: 'application/msword' + } + ], + data: { + value: { + expires: 1568107330518 + } + } + } +]; diff --git a/stories/corporate.stories.js b/stories/corporate.stories.js index 423b970a4..af9add24d 100644 --- a/stories/corporate.stories.js +++ b/stories/corporate.stories.js @@ -13,12 +13,14 @@ import { CorporateOrgChart } from '../src/renderer/corporate/common/corporate-or import { CorporateInformation } from '../src/renderer/corporate/common/corporate-information'; import { CorporateWizard } from '../src/renderer/corporate/wizard/corporate-wizard'; import { CorporateAddMember } from '../src/renderer/corporate/member/corporate-add-member'; +import { CorporateDocuments } from '../src/renderer/corporate/common/corporate-documents'; import { corporateApplications, corporateCapTable, dummyMembers, - corporateAttributes + corporateAttributes, + corporateDocuments } from './corporate-data'; storiesOf('Corporate', module).add('Dashboard', () => ( @@ -96,6 +98,14 @@ storiesOf('Corporate/Components', module) attributes={corporateAttributes} onEditAttribute={action('on edit attribute')} /> + )) + .add('Corporate Documents', () => ( + )); storiesOf('Corporate', module).add('Wizard', () => ); From a09a441babbf1291786895e341941f345365851c Mon Sep 17 00:00:00 2001 From: Andre Goncalves Date: Tue, 24 Sep 2019 10:58:39 +0100 Subject: [PATCH 141/207] feat: add missing buttons and actions --- .../common/corporate-information.jsx | 39 ++++++++++++++----- stories/corporate.stories.js | 2 + 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/renderer/corporate/common/corporate-information.jsx b/src/renderer/corporate/common/corporate-information.jsx index 0c1f71e32..3cb60d3e3 100644 --- a/src/renderer/corporate/common/corporate-information.jsx +++ b/src/renderer/corporate/common/corporate-information.jsx @@ -9,14 +9,16 @@ import { Table, TableHead, TableBody, - IconButton + IconButton, + Button } from '@material-ui/core'; import { IdCardIcon, SmallTableHeadRow, SmallTableRow, SmallTableCell, - EditTransparentIcon + EditTransparentIcon, + DeleteIcon } from 'selfkey-ui'; import { withStyles } from '@material-ui/core'; @@ -64,7 +66,7 @@ const renderAttributeValue = ({ data }) => data.value || ''; const renderAttributeTitle = attr => attr.type.content.title || 'No title provided'; const CorporateInformation = withStyles(styles)(props => { - const { classes, attributes = [], onEditAttribute } = props; + const { classes, attributes = [], onEditAttribute, onDeleteAttribute, onAddAttribute } = props; return ( @@ -145,12 +147,17 @@ const CorporateInformation = withStyles(styles)(props => { - - { - onEditAttribute(attr); - }} - /> + onEditAttribute(attr)} + > + + + onDeleteAttribute(attr)} + > + @@ -159,6 +166,20 @@ const CorporateInformation = withStyles(styles)(props => { + + + + +
diff --git a/stories/corporate.stories.js b/stories/corporate.stories.js index 423b970a4..4f3c3d82e 100644 --- a/stories/corporate.stories.js +++ b/stories/corporate.stories.js @@ -95,6 +95,8 @@ storiesOf('Corporate/Components', module) )); From 1827ef460b24dcc19eec872ea06335c8fd0ca165 Mon Sep 17 00:00:00 2001 From: Andre Goncalves Date: Tue, 24 Sep 2019 12:06:02 +0100 Subject: [PATCH 142/207] fix: selects the correct id attributes based on environment --- src/main/identity/id-attribute.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/identity/id-attribute.js b/src/main/identity/id-attribute.js index eb111d372..486c0808b 100644 --- a/src/main/identity/id-attribute.js +++ b/src/main/identity/id-attribute.js @@ -105,7 +105,7 @@ export class IdAttribute extends BaseModel { } static findAllByIdentityId(identityId) { - return this.query().where({ identityId }); + return this.query().where({ identityId, env }); } static async delete(id) { From 01da1d6f0d7836eb4aa64be16c66e2d5424b9820 Mon Sep 17 00:00:00 2001 From: Maxim Kovalov Date: Tue, 24 Sep 2019 15:46:24 +0300 Subject: [PATCH 143/207] feat(wizard): finish wire up --- src/common/identity/operations.js | 123 ++++++++++++++++-- src/common/identity/selectors.js | 94 ++++++++++++- src/common/identity/types.js | 4 +- src/main/identity/identity-service.js | 4 + .../wizard/corporate-wizard-container.jsx | 55 +++++--- .../corporate/wizard/corporate-wizard.jsx | 2 +- .../selfkey-id/main/containers/selfkey-id.js | 11 +- src/renderer/wallet/main/index.jsx | 9 ++ .../wallet/main/toolbar-container.jsx | 7 + src/renderer/wallet/main/toolbar.jsx | 113 ++++++++-------- 10 files changed, 333 insertions(+), 89 deletions(-) diff --git a/src/common/identity/operations.js b/src/common/identity/operations.js index 6217f748a..d71747062 100644 --- a/src/common/identity/operations.js +++ b/src/common/identity/operations.js @@ -5,6 +5,8 @@ import { push } from 'connected-react-router'; import identitySelectors from './selectors'; import identityActions from './actions'; import identityTypes from './types'; +import { Logger } from 'common/logger'; +const log = new Logger('identity-operations'); const loadCountriesOperation = () => async (dispatch, getState) => { const countryService = getGlobalContext().countryService; @@ -136,14 +138,90 @@ const createIdentityOperation = (walletId, type) => async (dispatch, getState) = return identity; }; -const createCorporateProfileOperation = () => async (dispatch, getState) => { +const createCorporateProfileOperation = data => async (dispatch, getState) => { const wallet = walletSelectors.getWallet(getState()); - const identity = await dispatch( - identityOperations.createIdentityOperation(wallet.id, 'corporate') - ); - await dispatch(identityOperations.updateIdentitySetupOperation(true, identity.id)); - await dispatch(identityOperations.unlockIdentityOperation(identity.id)); - await dispatch(push('/main/dashboard')); + let identity = null; + if (data.identityId) { + identity = identitySelectors.selectIdentityById(getState(), data.identityId); + } + const idAttributeTypes = identitySelectors.selectIdAttributeTypes(getState(), 'corporate'); + if (!identity) { + identity = await dispatch( + identityOperations.createIdentityOperation(wallet.id, 'corporate') + ); + } + const getTypeId = url => { + return idAttributeTypes.find(idAttributeType => idAttributeType.url === url).id; + }; + // TODO: XXX update to entity operations + await dispatch(identityOperations.updateIdentityNameOperation(data.entityName, identity.id)); + try { + await dispatch( + identityOperations.createIdAttributeOperation({ + typeId: getTypeId('http://platform.selfkey.org/schema/attribute/company-name.json'), + name: 'Legal Entity Name', + data: { value: data.entityName } + }) + ); + + await dispatch( + identityOperations.createIdAttributeOperation({ + typeId: getTypeId( + 'http://platform.selfkey.org/schema/attribute/legal-entity-type.json' + ), + name: 'Legal Entity Type', + data: { value: data.entityType } + }) + ); + + await dispatch( + identityOperations.createIdAttributeOperation({ + typeId: getTypeId( + 'http://platform.selfkey.org/schema/attribute/legal-jurisdiction.json' + ), + name: 'Legal Jurisdiction', + data: { value: data.jurisdiction } + }) + ); + + await dispatch( + identityOperations.createIdAttributeOperation({ + typeId: getTypeId( + 'http://platform.selfkey.org/schema/attribute/incorporation-date.json' + ), + name: 'Incorporation Date', + data: { value: data.creationDate } + }) + ); + + if (data.email) { + await dispatch( + identityOperations.createIdAttributeOperation({ + typeId: getTypeId('http://platform.selfkey.org/schema/attribute/email.json'), + name: 'Email', + data: { value: data.email } + }) + ); + } + + if (data.taxId) { + await dispatch( + identityOperations.createIdAttributeOperation({ + typeId: getTypeId( + 'http://platform.selfkey.org/schema/attribute/tax-id-number.json' + ), + name: 'Tax Id', + data: { value: data.taxId } + }) + ); + } + + await dispatch(identityOperations.updateIdentitySetupOperation(true, identity.id)); + await dispatch(identityOperations.unlockIdentityOperation(identity.id)); + await dispatch(push('/main/corporate-dashboard')); + } catch (error) { + log.error('failed to create corporate identity %s', error); + } }; const createSelfkeyIdOperation = (identityId, data) => async (dispatch, getState) => { @@ -190,6 +268,12 @@ const updateIdentitySetupOperation = (isSetupFinished, id) => async (dispatch, g await dispatch(identityActions.updateIdentity(identity)); }; +const updateIdentityNameOperation = (name, id) => async (dispatch, getState) => { + const identityService = getGlobalContext().identityService; + const identity = await identityService.updateIdentityName(name, id); + await dispatch(identityActions.updateIdentity(identity)); +}; + const loadIdentitiesOperation = walletId => async (dispatch, getState) => { let identityService = getGlobalContext().identityService; let identities = await identityService.loadIdentities(walletId); @@ -206,6 +290,19 @@ const switchProfileOperation = identity => async (dispatch, getState) => { await dispatch(identityOperations.unlockIdentityOperation(identity.id)); }; +const navigateToProfileOperation = () => async (dispatch, getState) => { + const identity = identitySelectors.selectCurrentIdentity(getState()); + + if (identity.type === 'individual') { + return dispatch(push('/main/selfkeyId')); + } + + if (identity.isSetupFinished) { + return dispatch(push('/main/corporate-dashboard')); + } + return dispatch(push(`/main/${identity.id}/setup-corporate-profile`)); +}; + export const operations = { loadCountriesOperation, loadRepositoriesOperation, @@ -230,7 +327,9 @@ export const operations = { updateDIDOperation, createIdentityOperation, createCorporateProfileOperation, - switchProfileOperation + switchProfileOperation, + navigateToProfileOperation, + updateIdentityNameOperation }; export const identityOperations = { @@ -330,6 +429,14 @@ export const identityOperations = { switchProfileOperation: createAliasedAction( identityTypes.IDENTITIES_SWITCH_PROFILE_OPERATION, operations.switchProfileOperation + ), + navigateToProfileOperation: createAliasedAction( + identityTypes.IDENTITIES_NAVIGATE_TO_PROFILE_OPERATION, + operations.navigateToProfileOperation + ), + updateIdentityNameOperation: createAliasedAction( + identityTypes.IDENTITIES_UPDATE_NAME_OPERATION, + operations.updateIdentityNameOperation ) }; diff --git a/src/common/identity/selectors.js b/src/common/identity/selectors.js index 00be857ad..35449be63 100644 --- a/src/common/identity/selectors.js +++ b/src/common/identity/selectors.js @@ -8,6 +8,12 @@ const LAST_NAME_ATTRIBUTE = 'http://platform.selfkey.org/schema/attribute/last-n const MIDDLE_NAME_ATTRIBUTE = 'http://platform.selfkey.org/schema/attribute/middle-name.json'; const COUNTRY_ATTRIBUTE = 'http://platform.selfkey.org/schema/attribute/country-of-residency.json'; +const ENTITY_NAME = 'http://platform.selfkey.org/schema/attribute/company-name.json'; +const ENTITY_TYPE = 'http://platform.selfkey.org/schema/attribute/legal-entity-type.json'; +const JURISDICTION = 'http://platform.selfkey.org/schema/attribute/legal-jurisdiction.json'; +const CREATION_DATE = 'http://platform.selfkey.org/schema/attribute/incorporation-date.json'; +const TAX_ID = 'http://platform.selfkey.org/schema/attribute/tax-id-number.json'; + const BASIC_ATTRIBUTES = { [FIRST_NAME_ATTRIBUTE]: 1, [LAST_NAME_ATTRIBUTE]: 1, @@ -17,6 +23,15 @@ const BASIC_ATTRIBUTES = { 'http://platform.selfkey.org/schema/attribute/address.json': 1 }; +const BASIC_CORPORATE_ATTRIBUTES = { + [ENTITY_NAME]: 1, + [ENTITY_TYPE]: 1, + [JURISDICTION]: 1, + [EMAIL_ATTRIBUTE]: 1, + [CREATION_DATE]: 1, + [TAX_ID]: 1 +}; + const selectIdentity = state => state.identity; const selectCountries = state => { @@ -70,8 +85,8 @@ const selectExpiredIdAttributeTypes = state => { .filter(attributeType => forceUpdateAttributes || attributeType.expires <= now); }; -const selectIdAttributeTypeByUrl = (state, url) => - identitySelectors.selectIdAttributeTypes(state).find(t => t.url === url); +const selectIdAttributeTypeByUrl = (state, url, entityType) => + identitySelectors.selectIdAttributeTypes(state, entityType).find(t => t.url === url); const selectUiSchemas = state => identitySelectors @@ -196,7 +211,75 @@ const selectAllIdentities = state => { const selectCurrentIdentity = state => { const tree = selectIdentity(state); - return tree.identitiesById[tree.currentIdentity]; + return selectIdentityById(state, tree.currentIdentity); +}; + +const selectCorporateJurisdictions = state => { + const idType = selectIdAttributeTypeByUrl( + state, + 'http://platform.selfkey.org/schema/attribute/legal-jurisdiction.json', + 'corporate' + ); + if (!idType) return []; + return idType.content.enum; +}; + +const selectCorporateLegalEntityTypes = state => { + const idType = selectIdAttributeTypeByUrl( + state, + 'http://platform.selfkey.org/schema/attribute/legal-entity-type.json', + 'corporate' + ); + if (!idType) return []; + return idType.content.enum; +}; + +const selectCorporateProfile = (state, id) => { + const identity = identitySelectors.selectIdentityById(state, id); + if (!identity) return {}; + const wallet = walletSelectors.getWallet(state); + const allAttributes = identitySelectors.selectFullIdAttributesByIds(state, identity.id); + + // FIXME: all base attribute types should be rendered (even if not created yet) + const basicAttributes = allAttributes.reduce( + (acc, curr) => { + const { url } = curr.type; + if (!BASIC_CORPORATE_ATTRIBUTES[url]) return acc; + if (acc.seen[url]) return acc; + acc.seen[url] = 1; + acc.attrs.push(curr); + return acc; + }, + { seen: {}, attrs: [] } + ).attrs; + const attributes = allAttributes.filter( + attr => !jsonSchema.containsFile(attr.type.content) && !basicAttributes.includes(attr) + ); + + // FIXME: document type should be determined by attribute type + const documents = allAttributes.filter(attr => jsonSchema.containsFile(attr.type.content)); + + const getBasicInfo = (type, basicAttrs) => { + let attr = basicAttrs.find(attr => attr.type.url === type); + if (!attr || !attr.data || !attr.data.value) return ''; + return attr.data.value; + }; + // TODO max: move profile picture to identity model + return { + identity, + wallet, + profilePicture: wallet.profilePicture, + allAttributes, + attributes, + basicAttributes, + documents, + email: getBasicInfo(EMAIL_ATTRIBUTE, basicAttributes), + taxId: getBasicInfo(TAX_ID, basicAttributes), + entityName: getBasicInfo(ENTITY_NAME, basicAttributes), + entityType: getBasicInfo(ENTITY_TYPE, basicAttributes), + creationDate: getBasicInfo(CREATION_DATE, basicAttributes), + jurisdiction: getBasicInfo(JURISDICTION, basicAttributes) + }; }; export const identitySelectors = { @@ -217,7 +300,10 @@ export const identitySelectors = { selectUiSchema, selectCurrentIdentity, selectIdentityById, - selectAllIdentities + selectAllIdentities, + selectCorporateJurisdictions, + selectCorporateLegalEntityTypes, + selectCorporateProfile }; export default identitySelectors; diff --git a/src/common/identity/types.js b/src/common/identity/types.js index 3c721eaba..0c8b6fdc8 100644 --- a/src/common/identity/types.js +++ b/src/common/identity/types.js @@ -42,7 +42,9 @@ export const identityTypes = { IDENTITIES_UPDATE_DID_OPERATION: 'identities/did/UPDATE', IDENTITIES_CREATE_OPERATION: 'identities/CREATE', IDENTITIES_CREATE_CORPORATE_PROFILE_OPERATION: 'identities/profile/corporate/CREATE', - IDENTITIES_SWITCH_PROFILE_OPERATION: 'identities/profile/SWITCH' + IDENTITIES_SWITCH_PROFILE_OPERATION: 'identities/profile/SWITCH', + IDENTITIES_NAVIGATE_TO_PROFILE_OPERATION: 'identities/profile/NAVIGATE', + IDENTITIES_UPDATE_NAME_OPERATION: 'identities/name/UPDATE' }; export default identityTypes; diff --git a/src/main/identity/identity-service.js b/src/main/identity/identity-service.js index 54440aa55..20c3d0eeb 100644 --- a/src/main/identity/identity-service.js +++ b/src/main/identity/identity-service.js @@ -128,6 +128,10 @@ export class IdentityService { return Identity.updateSetup({ id, isSetupFinished }); } + updateIdentityName(name, id) { + return Identity.updateName({ id, name }); + } + updateIdentityDID(did, id) { did = did.replace('did:selfkey:', ''); return Identity.updateDID({ did, id }); diff --git a/src/renderer/corporate/wizard/corporate-wizard-container.jsx b/src/renderer/corporate/wizard/corporate-wizard-container.jsx index 024e65774..bded30e8d 100644 --- a/src/renderer/corporate/wizard/corporate-wizard-container.jsx +++ b/src/renderer/corporate/wizard/corporate-wizard-container.jsx @@ -4,23 +4,38 @@ import { connect } from 'react-redux'; import { appSelectors } from 'common/app'; import { CorporateWizard } from './corporate-wizard'; import { push } from 'connected-react-router'; -import { identityOperations } from 'common/identity'; +import { identityOperations, identitySelectors } from 'common/identity'; class CorporateWizardContainerComponent extends Component { - state = { - errors: {}, - jurisdiction: null, - taxId: null, - entityType: null, - email: null, - entityName: null, - creationDate: null - }; + constructor(props) { + super(props); + const { basicIdentity = {} } = props; + this.state = { + errors: {}, + jurisdiction: basicIdentity.jurisdiction || '', + taxId: basicIdentity.taxId || null, + entityType: basicIdentity.entityType || '', + email: basicIdentity.email || null, + entityName: basicIdentity.entityName || null, + creationDate: basicIdentity.creationDate || null + }; + } + + componentDidMount() { + if (this.props.identity.type !== 'corporate') { + this.props.dispatch(identityOperations.navigateToProfileOperation()); + } + } + + componentDidUpdate() { + if (this.props.identity.type !== 'corporate') { + this.props.dispatch(identityOperations.navigateToProfileOperation()); + } + } handleFieldChange = name => evt => { const errors = { ...this.state.errors }; let value = evt; - if (evt && evt.target) { value = evt.target.value; } @@ -37,8 +52,8 @@ class CorporateWizardContainerComponent extends Component { handleContinueClick = evt => { evt && evt.preventDefault(); this.props.dispatch( - identityOperations.createCorporateProfileOperation( - _.pick( + identityOperations.createCorporateProfileOperation({ + ..._.pick( this.state, 'jurisdiction', 'taxId', @@ -46,8 +61,9 @@ class CorporateWizardContainerComponent extends Component { 'email', 'entityName', 'creationDate' - ) - ) + ), + identityId: this.props.match.params.identityId + }) ); }; @@ -87,6 +103,7 @@ class CorporateWizardContainerComponent extends Component { {...this.props} {...companyForm} isDisabled={this.isDisabled()} + onFieldChange={this.handleFieldChange} onContinueClick={this.handleContinueClick} onCancelClick={this.handleCancelClick} /> @@ -135,7 +152,13 @@ class CorporateWizardContainerComponent extends Component { const mapStateToProps = (state, props) => { return { - walletType: appSelectors.selectWalletType(state) + basicIdentity: identitySelectors.selectCorporateProfile( + state, + props.match.params.identityId + ), + walletType: appSelectors.selectWalletType(state), + jurisdictions: identitySelectors.selectCorporateJurisdictions(state), + entityTypes: identitySelectors.selectCorporateLegalEntityTypes(state) // members: dummyMembers }; }; diff --git a/src/renderer/corporate/wizard/corporate-wizard.jsx b/src/renderer/corporate/wizard/corporate-wizard.jsx index a2ff2bd84..bbff5ad5c 100644 --- a/src/renderer/corporate/wizard/corporate-wizard.jsx +++ b/src/renderer/corporate/wizard/corporate-wizard.jsx @@ -254,7 +254,7 @@ const CompanyInformation = withStyles(styles)(props => { diff --git a/src/renderer/selfkey-id/main/containers/selfkey-id.js b/src/renderer/selfkey-id/main/containers/selfkey-id.js index d81f690c7..590ac1749 100644 --- a/src/renderer/selfkey-id/main/containers/selfkey-id.js +++ b/src/renderer/selfkey-id/main/containers/selfkey-id.js @@ -1,6 +1,6 @@ import React, { Component } from 'react'; import { connect } from 'react-redux'; -import { identitySelectors } from 'common/identity'; +import { identitySelectors, identityOperations } from 'common/identity'; import SelfkeyId from '../components/selfkey-id'; import SelfkeyIdOverview from './selfkey-id-overview'; import SelfkeyIdApplications from './selfkey-id-applications'; @@ -16,6 +16,9 @@ class SelfkeyIdContainerComponent extends Component { async componentDidMount() { const { identity, dispatch } = this.props; const tab = this.props.tabValue; + if (this.props.identity.type !== 'individual') { + return this.props.dispatch(identityOperations.navigateToProfileOperation()); + } if (!identity.isSetupFinished) { await dispatch(push('/selfkeyIdCreate')); } @@ -27,6 +30,12 @@ class SelfkeyIdContainerComponent extends Component { this.setState({ tab }); }; + componentDidUpdate() { + if (this.props.identity.type !== 'individual') { + this.props.dispatch(identityOperations.navigateToProfileOperation()); + } + } + handleMarketplaceAccessClick = _ => this.props.dispatch(push(MARKETPLACE_ROOT_PATH)); render() { const { tab } = this.state; diff --git a/src/renderer/wallet/main/index.jsx b/src/renderer/wallet/main/index.jsx index c916732bd..9569a18bd 100644 --- a/src/renderer/wallet/main/index.jsx +++ b/src/renderer/wallet/main/index.jsx @@ -51,6 +51,7 @@ import CreateDIDProcessing from '../../selfkey-id/main/components/create-did-pro import HardwareWalletTransactionTimer from '../../transaction/send/timer'; import CorporateWizardContainer from '../../corporate/wizard/corporate-wizard-container'; import CorporateAddMemberContainer from '../../corporate/member/corporate-add-member-container'; +import { CorporateDashboardPage } from '../../corporate'; const styles = theme => ({ headerSection: { @@ -226,10 +227,18 @@ class Main extends Component { path={`${match.path}/create-corporate-profile`} component={CorporateWizardContainer} /> + +
); diff --git a/src/renderer/wallet/main/toolbar-container.jsx b/src/renderer/wallet/main/toolbar-container.jsx index 05e78902f..160e11664 100644 --- a/src/renderer/wallet/main/toolbar-container.jsx +++ b/src/renderer/wallet/main/toolbar-container.jsx @@ -40,7 +40,13 @@ class ToolbarContainer extends Component { this.props.dispatch(identityOperations.switchProfileOperation(identity)); }; + handleProfileNavigate = evt => { + evt.preventDefault(); + this.props.dispatch(identityOperations.navigateToProfileOperation()); + }; + handleProfileClick = evt => { + evt && evt.stopPropagation(); this.toggleProfile(!this.state.isProfileOpen); }; render() { @@ -57,6 +63,7 @@ class ToolbarContainer extends Component { onToggleMenu={this.toggleDrawer} primaryToken={config.constants.primaryToken} closeProfile={this.closeProfile} + onProfileNavigate={this.handleProfileNavigate} /> ); } diff --git a/src/renderer/wallet/main/toolbar.jsx b/src/renderer/wallet/main/toolbar.jsx index fa64fb60c..9302002ad 100644 --- a/src/renderer/wallet/main/toolbar.jsx +++ b/src/renderer/wallet/main/toolbar.jsx @@ -7,7 +7,6 @@ import { Typography, ClickAwayListener } from '@material-ui/core'; -import { Link } from 'react-router-dom'; import { MenuNewIcon, DropdownIcon, @@ -147,40 +146,41 @@ const defaultIdentityName = ({ type }) => type === 'individual' ? 'New individual' : 'New company'; const ProfileList = withStyles(profileStyle)( - ({ classes, profiles, isOpen, onProfileSelect, onClickCorporate }) => { + ({ classes, profiles, isOpen, onProfileSelect, onClickCorporate, closeProfile }) => { return ( isOpen && ( -
- {profiles && - profiles.map((el, index) => ( - - - {el.type === 'corporate' ? ( - - ) : ( - - )} - - - - {el.name || defaultIdentityName(el)} - - - {`${el.type.charAt(0).toUpperCase() + - el.type.slice(1)} Profile`} - + +
+ {profiles && + profiles.map((el, index) => ( + + + {el.type === 'corporate' ? ( + + ) : ( + + )} + + + + {el.name || defaultIdentityName(el)} + + + {`${el.type.charAt(0).toUpperCase() + + el.type.slice(1)} Profile`} + + - - ))} - -
- - {/* + ))} + +
+ + {/* + + + + - -
+
+ ) ); } ); -const Profile = withStyles(styles)(({ classes, profile, isOpen, onProfileClick, closeProfile }) => ( - - - - - {profile.type === 'individual' ? : } - - - - {profile.name || defaultIdentityName(profile)} - - - {profile.type === 'individual' ? 'Personal Profile' : 'Corporate Profile'} - - - +const Profile = withStyles(styles)( + ({ classes, profile, isOpen, onProfileClick, onProfileNavigate }) => ( + + {profile.type === 'individual' ? : } + + {profile.name || defaultIdentityName(profile)} + + {profile.type === 'individual' ? 'Personal Profile' : 'Corporate Profile'} + + - -)); + ) +); class Toolbar extends Component { render() { @@ -243,6 +238,7 @@ class Toolbar extends Component { closeProfile, selectedProfile, onProfileClick, + onProfileNavigate, onProfileSelect, profiles, onCreateCorporateProfileClick, @@ -292,7 +288,7 @@ class Toolbar extends Component { profile={selectedProfile} isOpen={isProfileOpen} onProfileClick={onProfileClick} - closeProfile={closeProfile} + onProfileNavigate={onProfileNavigate} />
@@ -305,6 +301,7 @@ class Toolbar extends Component { isOpen={isProfileOpen} onClickCorporate={onCreateCorporateProfileClick} onProfileSelect={onProfileSelect} + closeProfile={closeProfile} />
From 49bf99072a375493ac55f02d61041d00b1a5c507 Mon Sep 17 00:00:00 2001 From: designhorf Date: Tue, 24 Sep 2019 15:40:42 +0200 Subject: [PATCH 144/207] fix: button text size in toolbar dropdown --- src/renderer/wallet/main/toolbar.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/renderer/wallet/main/toolbar.jsx b/src/renderer/wallet/main/toolbar.jsx index 3b7841aa1..cc2e3ff1e 100644 --- a/src/renderer/wallet/main/toolbar.jsx +++ b/src/renderer/wallet/main/toolbar.jsx @@ -237,6 +237,7 @@ const ProfileList = withStyles(profileStyle)( variant="outlined" size="small" onClick={onClickCorporate} + className={classes.smallButton} > New Corporate Profile From dd7bb458613a824d016ef9a5756dc797c2036e73 Mon Sep 17 00:00:00 2001 From: Maxim Kovalov Date: Tue, 24 Sep 2019 16:47:10 +0300 Subject: [PATCH 145/207] feat(switcher): add wallet name and avatar --- src/common/wallet/selectors.js | 1 + src/renderer/home/loading.jsx | 2 +- .../main/components/hexagon-avatar.jsx | 26 +++++------ .../wallet/main/toolbar-container.jsx | 5 ++- src/renderer/wallet/main/toolbar.jsx | 43 ++++++++++++++++--- 5 files changed, 56 insertions(+), 21 deletions(-) diff --git a/src/common/wallet/selectors.js b/src/common/wallet/selectors.js index 089c1d6b4..48839086c 100644 --- a/src/common/wallet/selectors.js +++ b/src/common/wallet/selectors.js @@ -6,6 +6,7 @@ export const getWallet = state => { const ethereumPrice = ((getPrices(state) || {}).prices || []).filter(price => price.symbol === 'ETH')[0] || {}; wallet.balanceInFiat = wallet.balance * (ethereumPrice.priceUSD || 0); + wallet.profileName = wallet.profileName || wallet.name; wallet.name = 'Ethereum'; wallet.symbol = 'ETH'; wallet.price = ethereumPrice.priceUSD; diff --git a/src/renderer/home/loading.jsx b/src/renderer/home/loading.jsx index c5cabafc0..974e37764 100644 --- a/src/renderer/home/loading.jsx +++ b/src/renderer/home/loading.jsx @@ -11,7 +11,7 @@ const styles = theme => ({ backgroundImage: `url(${backgroundImage})`, minHeight: '100vh', textAlign: 'center', - padddingTop: '50px' + paddingTop: '200px' } }); diff --git a/src/renderer/selfkey-id/main/components/hexagon-avatar.jsx b/src/renderer/selfkey-id/main/components/hexagon-avatar.jsx index 032c5a706..8a1725793 100644 --- a/src/renderer/selfkey-id/main/components/hexagon-avatar.jsx +++ b/src/renderer/selfkey-id/main/components/hexagon-avatar.jsx @@ -29,18 +29,20 @@ const styles = theme => ({ } }); -export const HexagonAvatar = withStyles(styles)(({ classes, src = avatarPlaceholder, onClick }) => ( -
-
-
+export const HexagonAvatar = withStyles(styles)( + ({ classes, src = avatarPlaceholder, onClick, className }) => ( +
+
+
+
-
-)); + ) +); export default HexagonAvatar; diff --git a/src/renderer/wallet/main/toolbar-container.jsx b/src/renderer/wallet/main/toolbar-container.jsx index 160e11664..cb3abddfb 100644 --- a/src/renderer/wallet/main/toolbar-container.jsx +++ b/src/renderer/wallet/main/toolbar-container.jsx @@ -3,6 +3,7 @@ import Toolbar from './toolbar'; import config from 'common/config'; import { connect } from 'react-redux'; import { identitySelectors, identityOperations } from 'common/identity'; +import { walletSelectors } from 'common/wallet'; import { push } from 'connected-react-router'; class ToolbarContainer extends Component { @@ -57,6 +58,7 @@ class ToolbarContainer extends Component { isProfileOpen={isProfileOpen} profiles={this.props.profiles} selectedProfile={this.props.selectedProfile} + wallet={this.props.wallet} onProfileClick={this.handleProfileClick} onProfileSelect={this.handleProfileSelect} onCreateCorporateProfileClick={this.createCorporateProfile} @@ -71,5 +73,6 @@ class ToolbarContainer extends Component { export default connect(state => ({ profiles: identitySelectors.selectAllIdentities(state) || [], - selectedProfile: identitySelectors.selectCurrentIdentity(state) || {} + selectedProfile: identitySelectors.selectCurrentIdentity(state) || {}, + wallet: walletSelectors.getWallet(state) }))(ToolbarContainer); diff --git a/src/renderer/wallet/main/toolbar.jsx b/src/renderer/wallet/main/toolbar.jsx index 0562adb67..6534c6ba3 100644 --- a/src/renderer/wallet/main/toolbar.jsx +++ b/src/renderer/wallet/main/toolbar.jsx @@ -18,6 +18,7 @@ import { import PriceBox from '../../price-box'; import Sidebar from './sidebar'; import { featureIsEnabled } from 'common/feature-flags'; +import { HexagonAvatar } from '../../selfkey-id/main/components/hexagon-avatar'; const styles = theme => ({ wrapper: { @@ -116,6 +117,11 @@ const styles = theme => ({ }, priceBox: { paddingRight: '10px' + }, + profileAvatar: { + width: '40px', + height: '40px', + margin: 0 } }); @@ -176,14 +182,19 @@ const profileStyle = theme => fontSize: '10px', letterSpacing: '0.4px', width: '100%' + }, + profileListAvatar: { + width: '28px', + height: '28px', + margin: 0 } }); -const defaultIdentityName = ({ type }) => - type === 'individual' ? 'New individual' : 'New company'; +const defaultIdentityName = ({ type }, walletName) => + type === 'individual' ? walletName || 'New individual' : 'New company'; const ProfileList = withStyles(profileStyle)( - ({ classes, profiles, isOpen, onProfileSelect, onClickCorporate, closeProfile }) => { + ({ classes, profiles, wallet, isOpen, onProfileSelect, onClickCorporate, closeProfile }) => { return ( isOpen && ( @@ -199,13 +210,18 @@ const ProfileList = withStyles(profileStyle)( {el.type === 'corporate' ? ( + ) : wallet.profilePicture ? ( + ) : ( )} - {el.name || defaultIdentityName(el)} + {el.name || defaultIdentityName(el, wallet.profileName)} {`${el.type.charAt(0).toUpperCase() + @@ -252,11 +268,21 @@ const ProfileList = withStyles(profileStyle)( ); const Profile = withStyles(styles)( - ({ classes, profile, isOpen, onProfileClick, onProfileNavigate }) => ( + ({ classes, profile, wallet, isOpen, onProfileClick, onProfileNavigate }) => ( - {profile.type === 'individual' ? : } + + {profile.type === 'corporate' ? ( + + ) : wallet.profilePicture ? ( + + ) : ( + + )} + - {profile.name || defaultIdentityName(profile)} + + {profile.name || defaultIdentityName(profile, wallet.profileName)} + {profile.type === 'individual' ? 'Personal Profile' : 'Corporate Profile'} @@ -286,6 +312,7 @@ class Toolbar extends Component { onProfileNavigate, onProfileSelect, profiles, + wallet, onCreateCorporateProfileClick, primaryToken } = this.props; @@ -329,6 +356,7 @@ class Toolbar extends Component { > Date: Tue, 24 Sep 2019 16:55:54 +0300 Subject: [PATCH 146/207] feat(wizard): fix create --- src/renderer/corporate/wizard/corporate-wizard-container.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/renderer/corporate/wizard/corporate-wizard-container.jsx b/src/renderer/corporate/wizard/corporate-wizard-container.jsx index bded30e8d..e729da4c2 100644 --- a/src/renderer/corporate/wizard/corporate-wizard-container.jsx +++ b/src/renderer/corporate/wizard/corporate-wizard-container.jsx @@ -22,13 +22,13 @@ class CorporateWizardContainerComponent extends Component { } componentDidMount() { - if (this.props.identity.type !== 'corporate') { + if (this.props.identity && this.props.identity.type !== 'corporate') { this.props.dispatch(identityOperations.navigateToProfileOperation()); } } componentDidUpdate() { - if (this.props.identity.type !== 'corporate') { + if (this.props.identity && this.props.identity.type !== 'corporate') { this.props.dispatch(identityOperations.navigateToProfileOperation()); } } From 247edb1b19b1d21e4638b4186e75518e93601193 Mon Sep 17 00:00:00 2001 From: Maxim Kovalov Date: Tue, 24 Sep 2019 17:23:01 +0300 Subject: [PATCH 147/207] fix(wizard): layout --- src/renderer/corporate/wizard/corporate-wizard.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/corporate/wizard/corporate-wizard.jsx b/src/renderer/corporate/wizard/corporate-wizard.jsx index bbff5ad5c..a2ff2bd84 100644 --- a/src/renderer/corporate/wizard/corporate-wizard.jsx +++ b/src/renderer/corporate/wizard/corporate-wizard.jsx @@ -254,7 +254,7 @@ const CompanyInformation = withStyles(styles)(props => { From bb6f2caa6c3201d2a4a79f912b4dde097875e8a4 Mon Sep 17 00:00:00 2001 From: designhorf Date: Tue, 24 Sep 2019 16:35:41 +0200 Subject: [PATCH 148/207] fix: make avatar properly circle shape --- src/renderer/selfkey-id/main/components/hexagon-avatar.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/renderer/selfkey-id/main/components/hexagon-avatar.jsx b/src/renderer/selfkey-id/main/components/hexagon-avatar.jsx index 8a1725793..7f31338f0 100644 --- a/src/renderer/selfkey-id/main/components/hexagon-avatar.jsx +++ b/src/renderer/selfkey-id/main/components/hexagon-avatar.jsx @@ -22,6 +22,7 @@ const styles = theme => ({ backgroundPosition: '50%', backgroundRepeat: 'no-repeat', backgroundSize: 'cover', + borderRadius: '50%', height: '100%', transform: 'rotate(-60deg)', visibility: 'visible', From 7e889200fae2880b943cdb4d0fb05f025c369a5b Mon Sep 17 00:00:00 2001 From: designhorf Date: Tue, 24 Sep 2019 17:07:07 +0200 Subject: [PATCH 149/207] fix: hexagon avatar --- .../selfkey-id/main/components/hexagon-avatar.jsx | 8 +++++--- src/renderer/wallet/main/toolbar.jsx | 7 ++++++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/renderer/selfkey-id/main/components/hexagon-avatar.jsx b/src/renderer/selfkey-id/main/components/hexagon-avatar.jsx index 7f31338f0..4f6489fd3 100644 --- a/src/renderer/selfkey-id/main/components/hexagon-avatar.jsx +++ b/src/renderer/selfkey-id/main/components/hexagon-avatar.jsx @@ -22,20 +22,22 @@ const styles = theme => ({ backgroundPosition: '50%', backgroundRepeat: 'no-repeat', backgroundSize: 'cover', - borderRadius: '50%', height: '100%', transform: 'rotate(-60deg)', visibility: 'visible', width: '100%' + }, + smallAvatar: { + borderRadius: '50%' } }); export const HexagonAvatar = withStyles(styles)( - ({ classes, src = avatarPlaceholder, onClick, className }) => ( + ({ classes, smallAvatar = false, src = avatarPlaceholder, onClick, className }) => (
) : ( @@ -275,7 +276,11 @@ const Profile = withStyles(styles)( {profile.type === 'corporate' ? ( ) : wallet.profilePicture ? ( - + ) : ( )} From 8c824183db8cf0a11932279795893317d167a033 Mon Sep 17 00:00:00 2001 From: designhorf Date: Tue, 24 Sep 2019 17:16:11 +0200 Subject: [PATCH 150/207] fix: reduced gap between avatar and name --- src/renderer/wallet/main/toolbar.jsx | 42 +++++++++++++++------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/src/renderer/wallet/main/toolbar.jsx b/src/renderer/wallet/main/toolbar.jsx index db22e6ce9..d6306ce93 100644 --- a/src/renderer/wallet/main/toolbar.jsx +++ b/src/renderer/wallet/main/toolbar.jsx @@ -272,26 +272,28 @@ const ProfileList = withStyles(profileStyle)( const Profile = withStyles(styles)( ({ classes, profile, wallet, isOpen, onProfileClick, onProfileNavigate }) => ( - - {profile.type === 'corporate' ? ( - - ) : wallet.profilePicture ? ( - - ) : ( - - )} - - - - {profile.name || defaultIdentityName(profile, wallet.profileName)} - - - {profile.type === 'individual' ? 'Personal Profile' : 'Corporate Profile'} - + + + {profile.type === 'corporate' ? ( + + ) : wallet.profilePicture ? ( + + ) : ( + + )} + + + + {profile.name || defaultIdentityName(profile, wallet.profileName)} + + + {profile.type === 'individual' ? 'Personal Profile' : 'Corporate Profile'} + + Date: Wed, 25 Sep 2019 11:23:27 +0100 Subject: [PATCH 151/207] fix: removes feature flag to container on the toolbar component --- src/common/feature-flags.js | 2 +- .../wallet/main/toolbar-container.jsx | 2 ++ src/renderer/wallet/main/toolbar.jsx | 36 +++++++++++-------- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/src/common/feature-flags.js b/src/common/feature-flags.js index e44d67819..9c2fcf3a8 100644 --- a/src/common/feature-flags.js +++ b/src/common/feature-flags.js @@ -1,4 +1,4 @@ -import config from './config'; +import config from 'common/config'; const featureIsEnabled = featureName => { const snakeCase = featureName diff --git a/src/renderer/wallet/main/toolbar-container.jsx b/src/renderer/wallet/main/toolbar-container.jsx index cb3abddfb..483081318 100644 --- a/src/renderer/wallet/main/toolbar-container.jsx +++ b/src/renderer/wallet/main/toolbar-container.jsx @@ -5,6 +5,7 @@ import { connect } from 'react-redux'; import { identitySelectors, identityOperations } from 'common/identity'; import { walletSelectors } from 'common/wallet'; import { push } from 'connected-react-router'; +import { featureIsEnabled } from 'common/feature-flags'; class ToolbarContainer extends Component { state = { @@ -66,6 +67,7 @@ class ToolbarContainer extends Component { primaryToken={config.constants.primaryToken} closeProfile={this.closeProfile} onProfileNavigate={this.handleProfileNavigate} + showCorporate={featureIsEnabled('corporate')} /> ); } diff --git a/src/renderer/wallet/main/toolbar.jsx b/src/renderer/wallet/main/toolbar.jsx index d6306ce93..d14c9d775 100644 --- a/src/renderer/wallet/main/toolbar.jsx +++ b/src/renderer/wallet/main/toolbar.jsx @@ -17,7 +17,6 @@ import { } from 'selfkey-ui'; import PriceBox from '../../price-box'; import Sidebar from './sidebar'; -import { featureIsEnabled } from 'common/feature-flags'; import { HexagonAvatar } from '../../selfkey-id/main/components/hexagon-avatar'; const styles = theme => ({ @@ -194,7 +193,16 @@ const defaultIdentityName = ({ type }, walletName) => type === 'individual' ? walletName || 'New individual' : 'New company'; const ProfileList = withStyles(profileStyle)( - ({ classes, profiles, wallet, isOpen, onProfileSelect, onClickCorporate, closeProfile }) => { + ({ + classes, + profiles, + wallet, + isOpen, + onProfileSelect, + onClickCorporate, + closeProfile, + showCorporate + }) => { return ( isOpen && ( @@ -231,23 +239,23 @@ const ProfileList = withStyles(profileStyle)( ))} - {featureIsEnabled('corporate') && ( + {showCorporate && (
{/* - - - - */} + + + + */} + + + + + + + + + + + + + ); +}); diff --git a/src/renderer/selfkey-id/main/components/create-did.jsx b/src/renderer/did/create-did-popup-container.jsx similarity index 75% rename from src/renderer/selfkey-id/main/components/create-did.jsx rename to src/renderer/did/create-did-popup-container.jsx index 2956d6074..e328bfe38 100644 --- a/src/renderer/selfkey-id/main/components/create-did.jsx +++ b/src/renderer/did/create-did-popup-container.jsx @@ -1,8 +1,8 @@ import React, { Component } from 'react'; import { connect } from 'react-redux'; import config from 'common/config'; -import { Popup } from '../../../common/popup'; -import { CreateDIDContent } from './create-did-content'; + +import { CreateDIDPopup } from './create-did-popup'; import { getLocale } from 'common/locale/selectors'; import { getTokens } from 'common/wallet-tokens/selectors'; import { getFiatCurrency } from 'common/fiatCurrency/selectors'; @@ -16,7 +16,7 @@ import { push } from 'connected-react-router'; const CRYPTOCURRENCY = config.constants.primaryToken; -class CreateDIDComponent extends Component { +class CreateDIDPopupContainerComponent extends Component { state = { open: true, isConfirmationOpen: false @@ -54,29 +54,24 @@ class CreateDIDComponent extends Component { this.props.dispatch(push(this.props.didOriginUrl)); }; + handleLearnHowClicked = e => { + window.openExternal(e, 'https://help.selfkey.org/'); + }; + render() { const { open } = this.state; const { usdFee, ethFee, cryptoCurrency } = this.getPaymentParameters(); return ( - - - - - + ); } } @@ -95,6 +90,6 @@ const mapStateToProps = (state, props) => { }; }; -export const CreateDID = connect(mapStateToProps)(CreateDIDComponent); +export const CreateDIDPopupContainer = connect(mapStateToProps)(CreateDIDPopupContainerComponent); -export default CreateDID; +export default CreateDIDPopupContainer; diff --git a/src/renderer/did/create-did-popup.jsx b/src/renderer/did/create-did-popup.jsx new file mode 100644 index 000000000..14fffe8b6 --- /dev/null +++ b/src/renderer/did/create-did-popup.jsx @@ -0,0 +1,148 @@ +import React, { Component } from 'react'; +import { Grid, withStyles, Typography, Button, IconButton, Divider } from '@material-ui/core'; +import { Popup } from '../common/popup'; +import { KeyTooltip, TooltipArrow, PaymentIcon, InfoTooltip } from 'selfkey-ui'; + +const styles = theme => ({ + footer: { + paddingTop: '40px' + }, + actions: { + '&>button': { + marginRight: '20px', + marginTop: '40px' + } + }, + networkFee: { + fontWeight: 600, + marginBottom: '4px' + }, + textRight: { + textAlign: 'right' + }, + bottomSpace: { + marginBottom: '30px' + }, + link: { + cursor: 'pointer', + color: '#00C0D9', + textDecoration: 'none' + }, + tooltipIcon: { + padding: '0px 0 3px 10px', + '& svg': { + height: '10px !important', + width: '10px !important' + } + }, + divider: { + marginBottom: '20px' + }, + bottomSpace2: { + marginBottom: '20px' + } +}); + +class CreateDIDPopupComponent extends Component { + render() { + const { + classes, + usdNetworkFee, + ethNetworkFee, + tooltipNetworkFee, + onConfirm, + onCancel, + onLearnHowClicked, + open + } = this.props; + + return ( + + + + + + + + + + Decentralised ID Required + + + + + Getting your DID ( + + what’s this? + + ) and registering on the SelfKey Network requires an Ethereum + transaction. This is a one time only transaction. + + + + + + + + Network Transaction Fee + + + + + ${usdNetworkFee.toLocaleString()} + + + {ethNetworkFee.toLocaleString()} ETH + + {tooltipNetworkFee} + + + } + > + + + + + + + + +
+ + +
+
+
+
+
+
+ ); + } +} + +export const CreateDIDPopup = withStyles(styles)(CreateDIDPopupComponent); +export default CreateDIDPopup; diff --git a/src/renderer/selfkey-id/main/components/create-did-processing.jsx b/src/renderer/did/create-did-processing-container.jsx similarity index 64% rename from src/renderer/selfkey-id/main/components/create-did-processing.jsx rename to src/renderer/did/create-did-processing-container.jsx index c0ee84767..79ce3be8d 100644 --- a/src/renderer/selfkey-id/main/components/create-did-processing.jsx +++ b/src/renderer/did/create-did-processing-container.jsx @@ -1,10 +1,10 @@ import React, { Component } from 'react'; import { connect } from 'react-redux'; import { push } from 'connected-react-router'; -import { TransactionProcessingPopup } from '../../../common/transaction-processing-popup'; +import { TransactionProcessingPopup } from '../common/transaction-processing-popup'; import { walletSelectors } from 'common/wallet'; -class CreateDIDProcessingComponent extends Component { +class CreateDIDProcessingContainerComponent extends Component { handleCloseAction = _ => { this.props.dispatch(push(this.props.didOriginUrl)); }; @@ -25,6 +25,8 @@ const mapStateToProps = (state, props) => { return { didOriginUrl: walletSelectors.getDidOriginUrl(state) }; }; -export const CreateDIDProcessing = connect(mapStateToProps)(CreateDIDProcessingComponent); +export const CreateDIDProcessingContainer = connect(mapStateToProps)( + CreateDIDProcessingContainerComponent +); -export default CreateDIDProcessing; +export default CreateDIDProcessingContainer; diff --git a/src/renderer/did/index.js b/src/renderer/did/index.js new file mode 100644 index 000000000..328500d2b --- /dev/null +++ b/src/renderer/did/index.js @@ -0,0 +1,4 @@ +export { AssociateDIDContainer } from './associate-did-container'; +export { RegisterDidCardContainer } from './register-did-card-container'; +export { CreateDIDPopupContainer } from './create-did-popup-container'; +export { CreateDIDProcessingContainer } from './create-did-processing-container'; diff --git a/src/renderer/did/register-did-card-container.js b/src/renderer/did/register-did-card-container.js new file mode 100644 index 000000000..f5922aa62 --- /dev/null +++ b/src/renderer/did/register-did-card-container.js @@ -0,0 +1,29 @@ +import React, { Component } from 'react'; +import { connect } from 'react-redux'; +import { RegisterDidCard } from './register-did-card'; +import { walletOperations, walletSelectors } from 'common/wallet'; + +const SELFKEY_ID_PATH = '/main/selfkeyId'; + +class RegisterDidCardContainerComponent extends Component { + handleRegisterDidClick = _ => + this.props.dispatch(walletOperations.startCreateDidFlow(SELFKEY_ID_PATH)); + handleAssociateDidClick = _ => + this.props.dispatch(walletOperations.startAssociateDidFlow(SELFKEY_ID_PATH)); + + render() { + return ( + + ); + } +} + +export const RegisterDidCardContainer = connect(state => ({ + wallet: walletSelectors.getWallet(state) +}))(RegisterDidCardContainerComponent); + +export default RegisterDidCardContainer; diff --git a/src/renderer/did/register-did-card.jsx b/src/renderer/did/register-did-card.jsx new file mode 100644 index 000000000..26b977c09 --- /dev/null +++ b/src/renderer/did/register-did-card.jsx @@ -0,0 +1,128 @@ +import React, { Component } from 'react'; +import { + CardContent, + Card, + CardHeader, + Grid, + Typography, + Button, + withStyles +} from '@material-ui/core'; +import { DIDIcon } from 'selfkey-ui'; + +const styles = theme => ({ + hr: { + backgroundColor: '#303C49', + border: 'none', + boxSizing: 'border-box', + height: '1px', + margin: '5px 16px' + }, + info: { + padding: '25px 30px' + }, + regularText: { + '& span': { + fontWeight: 400 + } + }, + didButtons: { + marginTop: '20px' + }, + transaction: { + alignItems: 'center', + display: 'flex' + }, + extraSpace: { + marginRight: '4px' + } +}); + +class RegisterDidCardComponent extends Component { + render() { + const { classes } = this.props; + return ( + + +
+ + + + + + + + + + + Register on the SelfKey Network to get your DID. + + + + + + + Use a DID when accesing different services in the marketplace. + Once created you’ll see it under your profile. + +
+ + Getting a DID requires an Ethereum transaction. This is a one + time only transaction. + + + + + + + + + {this.props.pending && ( + + + Processing transaction..Please wait + + + )} + +
+
+
+
+
+ ); + } +} + +export const RegisterDidCard = withStyles(styles)(RegisterDidCardComponent); + +export default RegisterDidCard; diff --git a/src/renderer/selfkey-id/main/components/associate-did.jsx b/src/renderer/selfkey-id/main/components/associate-did.jsx deleted file mode 100644 index 01eba413d..000000000 --- a/src/renderer/selfkey-id/main/components/associate-did.jsx +++ /dev/null @@ -1,259 +0,0 @@ -import React, { Component } from 'react'; -import { push } from 'connected-react-router'; -import { connect } from 'react-redux'; -import { walletOperations, walletSelectors } from 'common/wallet'; -import { identitySelectors } from 'common/identity'; -import { - Grid, - Button, - Typography, - withStyles, - Input, - CircularProgress, - Paper -} from '@material-ui/core'; -import { MergeIcon, ModalWrap, ModalHeader, ModalBody, CloseButtonIcon } from 'selfkey-ui'; - -const styles = theme => ({ - icon: { - width: '66px', - height: '71px' - }, - modalPosition: { - position: 'static', - marginTop: '30px' - }, - loading: { - position: 'relative', - marginLeft: '10px', - top: '5px' - }, - searching: { - height: '19px', - width: '242px', - color: '#00C0D9', - fontFamily: 'Lato', - fontSize: '13px', - lineHeight: '19px', - textTransform: 'none', - marginLeft: '10px' - }, - errorText: { - height: '19px', - width: '242px', - color: '#FE4B61', - fontFamily: 'Lato', - fontSize: '13px', - lineHeight: '19px' - }, - errorColor: { - color: '#FE4B61 !important', - border: '2px solid #FE4B61 !important', - backgroundColor: 'rgba(255,46,99,0.09) !important' - }, - input: { - width: '100%', - '&::-webkit-input-placeholder': { - fontSize: '14px', - color: '#93B0C1' - } - }, - bold: { - fontWeight: 600 - }, - closeIcon: { - cursor: 'pointer', - position: 'absolute', - marginLeft: '759px', - marginTop: '-20px' - }, - label: { - marginBottom: '10px' - }, - buttoms: { - marginTop: '30px' - } -}); - -class AssociateDIDComponent extends Component { - state = { - did: '', - searching: false - }; - - componentDidMount() { - this.resetErrors(); - } - - componentDidUpdate(prevProps) { - if (prevProps.associateError !== this.props.associateError) { - if (this.state.searching) { - if (this.props.associateError === 'none') { - this.handleBackClick(); - } - this.setState({ searching: false }); - } - } - } - - resetErrors = () => { - this.props.dispatch(walletOperations.resetAssociateDID()); - }; - - handleBackClick = evt => { - evt && evt.preventDefault(); - this.props.dispatch(push(this.props.didOriginUrl)); - }; - - handleFieldChange = async event => { - let value = event.target.value; - await this.resetErrors(); - this.setState({ did: value }); - }; - - associateDID = async () => { - await this.resetErrors(); - let did = this.state.did; - if (did !== '') { - await this.props.dispatch( - walletOperations.updateWalletDID(this.props.identity.walletId, did) - ); - } else { - this.setState({ searching: false }); - } - }; - - handleSubmit = () => { - this.setState({ searching: true }, async () => { - await this.associateDID(); - }); - }; - - render() { - const { classes, associateError } = this.props; - const { did, searching } = this.state; - const isEmpty = did === '' || did === undefined; - const hasAssociateError = associateError !== '' && associateError !== 'none' && did !== ''; - const didInputClass = `${classes.input} ${ - hasAssociateError && !searching ? classes.errorColor : '' - }`; - - return ( - - - - - - - - - Associate DID with this wallet - - - - - - - - - - - - If you already registered on the SelfKey Network, you can - associate your existing DID number with this wallet. Just - copy/paste it below. - -
- - DID Number - {searching && ( - - - - - - Please wait. Checking the blockchain for DID{' '} - information. - - - )} - - - {!searching && hasAssociateError && ( - - {associateError} - - )} - - - - - - - - - -
-
-
-
-
-
- ); - } -} - -const mapStateToProps = (state, props) => { - return { - identity: identitySelectors.selectCurrentIdentity(state), - associateError: walletSelectors.getAssociateError(state), - didOriginUrl: walletSelectors.getDidOriginUrl(state) - }; -}; - -export const AssociateDID = connect(mapStateToProps)(withStyles(styles)(AssociateDIDComponent)); - -export default AssociateDID; diff --git a/src/renderer/selfkey-id/main/components/create-did-content.jsx b/src/renderer/selfkey-id/main/components/create-did-content.jsx deleted file mode 100644 index 0acf514d8..000000000 --- a/src/renderer/selfkey-id/main/components/create-did-content.jsx +++ /dev/null @@ -1,145 +0,0 @@ -import React, { Component } from 'react'; -import { Grid, withStyles, Typography, Button, IconButton, Divider } from '@material-ui/core'; - -import { KeyTooltip, TooltipArrow, PaymentIcon, InfoTooltip } from 'selfkey-ui'; - -const styles = theme => ({ - footer: { - paddingTop: '40px' - }, - actions: { - '&>button': { - marginRight: '20px', - marginTop: '40px' - } - }, - networkFee: { - fontWeight: 600, - marginBottom: '4px' - }, - textRight: { - textAlign: 'right' - }, - bottomSpace: { - marginBottom: '30px' - }, - link: { - cursor: 'pointer', - color: '#00C0D9', - textDecoration: 'none' - }, - tooltipIcon: { - padding: '0px 0 3px 10px', - '& svg': { - height: '10px !important', - width: '10px !important' - } - }, - divider: { - marginBottom: '20px' - }, - bottomSpace2: { - marginBottom: '20px' - } -}); - -class CreateDIDContentComponent extends Component { - render() { - const { - classes, - usdNetworkFee, - ethNetworkFee, - tooltipNetworkFee, - onConfirm, - onCancel, - learnHowURL - } = this.props; - - return ( - - - - - - - - - Decentralised ID Required - - - - - Getting your DID ( - { - window.openExternal(e, learnHowURL); - }} - > - what’s this? - - ) and registering on the SelfKey Network requires an Ethereum - transaction. This is a one time only transaction. - - - - - - - - Network Transaction Fee - - - - - ${usdNetworkFee.toLocaleString()} - - - {ethNetworkFee.toLocaleString()} ETH - - {tooltipNetworkFee} - - - } - > - - - - - - - - -
- - -
-
-
-
-
- ); - } -} - -export const CreateDIDContent = withStyles(styles)(CreateDIDContentComponent); -export default CreateDIDContent; diff --git a/src/renderer/selfkey-id/main/components/selfkey-id-overview.jsx b/src/renderer/selfkey-id/main/components/selfkey-id-overview.jsx index a7ad230ed..7033e8586 100644 --- a/src/renderer/selfkey-id/main/components/selfkey-id-overview.jsx +++ b/src/renderer/selfkey-id/main/components/selfkey-id-overview.jsx @@ -28,8 +28,7 @@ import { SmallTableHeadRow, SmallTableRow, SmallTableCell, - FileAudioIcon, - DIDIcon + FileAudioIcon } from 'selfkey-ui'; import { HexagonAvatar } from './hexagon-avatar'; @@ -84,16 +83,6 @@ const styles = theme => ({ textOverflow: 'ellipsis', whiteSpace: 'nowrap', maxWidth: '222px' - }, - didButtons: { - marginTop: '20px' - }, - transaction: { - alignItems: 'center', - display: 'flex' - }, - extraSpace: { - marginRight: '4px' } }); @@ -175,7 +164,6 @@ class SelfkeyIdOverviewComponent extends Component { firstName, lastName, middleName, - wallet, identity } = this.props; @@ -220,112 +208,7 @@ class SelfkeyIdOverviewComponent extends Component { - {!identity.did && ( - - - -
- - - - - - - - - - - Register on the SelfKey Network to get - your DID. - - - - - - - Use a DID when accesing different services - in the marketplace. Once created you’ll see - it under your profile. - -
- - Getting a DID requires an Ethereum - transaction. This is a one time only - transaction. - - - - - - - - - {wallet.didPending && ( - - - Processing transaction..Please - wait - - - )} - -
-
-
-
-
-
- )} + {this.props.didCard && {this.props.didCard}} this.props.dispatch(identityOperations.removeIdAttributeOperation(attributeId)); - handleGetDid = _ => this.props.dispatch(walletOperations.startCreateDidFlow(SELFKEY_ID_PATH)); - handleEnterDid = _ => - this.props.dispatch(walletOperations.startAssociateDidFlow(SELFKEY_ID_PATH)); - handleEditAttribute = attribute => { this.setState({ popup: 'edit-attribute', editAttribute: attribute }); }; @@ -76,6 +71,7 @@ class SelfkeyIdOverviewContainerComponent extends Component { /> )} : null} onGetDid={this.handleGetDid} onEnterDid={this.handleEnterDid} onDeleteAttribute={this.handleDeleteAttribute} diff --git a/src/renderer/selfkey-id/main/index.js b/src/renderer/selfkey-id/main/index.js index 876b4a582..51b0af413 100644 --- a/src/renderer/selfkey-id/main/index.js +++ b/src/renderer/selfkey-id/main/index.js @@ -1,2 +1 @@ export { SelfkeyIdContainer } from './containers/selfkey-id'; -export { AssociateDID } from './components/associate-did'; diff --git a/src/renderer/wallet/main/index.jsx b/src/renderer/wallet/main/index.jsx index 9569a18bd..c9b2dcc07 100644 --- a/src/renderer/wallet/main/index.jsx +++ b/src/renderer/wallet/main/index.jsx @@ -20,7 +20,12 @@ import { MarketplaceOrdersPage } from '../../marketplace'; -import { SelfkeyIdContainer, AssociateDID } from '../../selfkey-id/main'; +import { SelfkeyIdContainer } from '../../selfkey-id/main'; +import { + AssociateDIDContainer, + CreateDIDPopupContainer, + CreateDIDProcessingContainer +} from '../../did'; import Transfer from '../../transaction/send'; import AdvancedTransaction from '../../transaction/send/advanced-transaction'; import ReceiveTransfer from '../../transaction/receive'; @@ -46,8 +51,6 @@ import { CurrentApplication, ApplicationInProgress } from '../../kyc'; import md5 from 'md5'; import ReactPiwik from 'react-piwik'; -import CreateDID from '../../selfkey-id/main/components/create-did'; -import CreateDIDProcessing from '../../selfkey-id/main/components/create-did-processing'; import HardwareWalletTransactionTimer from '../../transaction/send/timer'; import CorporateWizardContainer from '../../corporate/wizard/corporate-wizard-container'; import CorporateAddMemberContainer from '../../corporate/member/corporate-add-member-container'; @@ -121,7 +124,7 @@ class Main extends Component { path={`${match.path}/selfkeyIdApplications`} render={props => } /> - + - + ( + + )) + .add('pending', () => ( + + )); + +storiesOf('DID/CreateDIDPopup', module).add('default', () => ( + +)); + +storiesOf('DID/AssociateDid', module) + .add('default', () => ( + + )) + .add('filled', () => ( + + )) + .add('searching', () => ( + + )) + .add('error', () => ( + + )); From 661ff7d24196c105e63b56922f4530126483df42 Mon Sep 17 00:00:00 2001 From: Andre Goncalves Date: Thu, 26 Sep 2019 13:26:29 +0100 Subject: [PATCH 155/207] fix: refactor manage applications for store integration --- src/common/kyc/index.js | 11 +- src/common/marketplace/vendors/index.js | 5 + src/main/kyc/kyc-application-service.js | 6 + .../components/selfkey-id-applications.jsx | 110 ++++--- .../containers/selfkey-id-applications.js | 272 +++++------------- .../selfkey-id/main/containers/selfkey-id.js | 5 +- 6 files changed, 148 insertions(+), 261 deletions(-) diff --git a/src/common/kyc/index.js b/src/common/kyc/index.js index dcf3ab4d9..405045a30 100644 --- a/src/common/kyc/index.js +++ b/src/common/kyc/index.js @@ -62,6 +62,9 @@ export const kycSelectors = { kycSelector(state) { return state.kyc; }, + relyingPartiesSelector(state) { + return this.kycSelector(state).relyingPartiesByName; + }, relyingPartySelector(state, rpName) { if (!rpName) return null; return this.kycSelector(state).relyingPartiesByName[rpName]; @@ -350,6 +353,8 @@ const loadRelyingPartyOperation = ( if (authenticate) { applications = await session.listKYCApplications(); for (const application of applications) { + const template = templates.find(t => t.id === application.template); + await dispatch( kycOperations.updateApplicationsOperation({ id: application.id, @@ -360,11 +365,7 @@ const loadRelyingPartyOperation = ( owner: application.owner, scope: application.scope, applicationDate: application.createdAt, - // TODO: this is only a workaround for now, we must change this in the future - title: - Object.keys(application.questions).length > 0 - ? 'Bank Account' - : 'Incorporation' + title: template ? template.name : rpName }) ); } diff --git a/src/common/marketplace/vendors/index.js b/src/common/marketplace/vendors/index.js index 569b8ba58..8b6237943 100644 --- a/src/common/marketplace/vendors/index.js +++ b/src/common/marketplace/vendors/index.js @@ -61,6 +61,11 @@ export const vendorSelectors = { vendorSelectors .selectVendorRoot(state) .all.map(id => vendorSelectors.selectVendorRoot(state).byId[id]), + selectActiveVendors: state => + vendorSelectors + .selectVendorRoot(state) + .all.filter(id => vendorSelectors.selectVendorRoot(state).byId[id].status === 'active') + .map(id => vendorSelectors.selectVendorRoot(state).byId[id]), selectVendorsForCategory: (state, category, status = 'active') => vendorSelectors .selectVendors(state) diff --git a/src/main/kyc/kyc-application-service.js b/src/main/kyc/kyc-application-service.js index b9d824079..59117c369 100644 --- a/src/main/kyc/kyc-application-service.js +++ b/src/main/kyc/kyc-application-service.js @@ -14,6 +14,12 @@ export class KycApplicationService { }; editEntry = entry => { + // Don't update rpName or title, they should be + // set on creation. Otherwise rp syncing will + // overwrite this field + delete entry.rpName; + delete entry.title; + return KycApplication.update(entry); }; diff --git a/src/renderer/selfkey-id/main/components/selfkey-id-applications.jsx b/src/renderer/selfkey-id/main/components/selfkey-id-applications.jsx index 4c8ff3f03..1d174faaf 100644 --- a/src/renderer/selfkey-id/main/components/selfkey-id-applications.jsx +++ b/src/renderer/selfkey-id/main/components/selfkey-id-applications.jsx @@ -263,61 +263,59 @@ class SelfkeyIdApplicationsComponent extends Component { ); - renderApplicationRefreshModal() { - const { classes } = this.props; - return ( - ( + + - - - - Application status updated successfully. - - - - - - - + + + Application status updated successfully. + + + + + + - - ); - } +
+ + ); render() { - const { classes, showApplicationRefreshModal, loading, config, applications } = this.props; - - if (loading) { - return this.renderLoadingScreen(); - } + const { classes, showApplicationRefreshModal, loading, applications, vendors } = this.props; const getRpInfo = (rpName, field) => { - return config.relyingPartyInfo[rpName][field]; + const vendor = vendors.find(v => v.vendorId === rpName); + if (vendor && vendor[field]) { + return vendor[field]; + } else { + return 'N/A'; + } }; - const getRpName = title => { - return title.toLowerCase().startsWith('bank account') - ? 'Bank Accounts' - : 'Incorporations'; - }; + const getRpName = application => getRpInfo(application.rpName, 'name'); + + if (loading) { + return this.renderLoadingScreen(); + } if (!loading && applications && applications.length === 0) { return ( @@ -376,16 +374,10 @@ class SelfkeyIdApplicationsComponent extends Component { alignItems="baseline" > - {/* Until the scheduler (and associate vendor airtable) is released, we are going to use - the application's title because we are using the same rpName for BAM and Incorporations. */} - {/* {item.rpName.charAt(0).toUpperCase() + - item.rpName.slice(1)} */} - {getRpName(item.title)} + {item.title} - -{' '} - {item.title.charAt(0).toUpperCase() + - item.title.slice(1)} + {getRpName(item)}
- this.props.onApplicationAddDocuments( + this.props.onApplicationAdditionalRequirements( item.id, item.rpName ) } - handleRefresh={() => - this.props.onApplicationRefresh(item.id) - } + handleRefresh={() => this.props.onApplicationRefresh(item)} tooltip={moment(new Date(item.updatedAt)).format( 'DD MMM YYYY' )} @@ -479,7 +470,10 @@ class SelfkeyIdApplicationsComponent extends Component { Provider Contact - {getRpInfo(item.rpName, 'email')} + {getRpInfo( + item.rpName, + 'contactEmail' + )} { - await this.props.dispatch(kycOperations.setProcessing(true)); - await this.props.dispatch( - kycOperations.loadRelyingParty( - 'incorporations', - authenticate, - afterAuthRoute, - cancelRoute - ) - ); - }); - } - - // try to load existing kyc_applications data + // load marketplace store + await this.props.dispatch(marketplaceOperations.loadMarketplaceOperation()); + // load existing kyc_applications data await this.props.dispatch(kycOperations.loadApplicationsOperation()); - // this is needed otherwise the rp keeps loading (stuck) - if (!this.props.incorporations || !this.props.incorporations.length) { - await this.props.dispatch(incorporationsOperations.loadIncorporationsOperation()); - } + await this.loadRelyingParties(vendors); } async componentDidUpdate(prevProps) { - if (prevProps.rp !== this.props.rp) { - if (this.props.rp.authenticated) { - await this.props.dispatch(kycOperations.loadApplicationsOperation()); - } - this.setState({ loading: false }, () => { - if (this.state.refreshing) { - if (this.state.applicationId) { - // try to refresh again after loading relying party - this.handleApplicationRefresh(this.state.applicationId); - } - } - if (this.state.addingDocuments) { - if (this.state.applicationId) { - // try to refresh again after loading relying party - this.handleApplicationAddDocuments( - this.state.applicationId, - this.state.rpName - ); - } - } - }); + if (prevProps.vendors.length !== this.props.vendors.length) { + await this.loadRelyingParties(this.props.vendors); } } - handleApplicationAddDocuments = (id, rpName) => { - const { rp, afterAuthRoute } = this.props; - const cancelRoute = `/main/selfkeyId`; - const authenticate = true; - - // if relying party not loaded, try again - if (!rp || !rp.authenticated) { - this.setState( - { loading: true, addingDocuments: true, applicationId: id, rpName }, - async () => { - await this.props.dispatch( - kycOperations.loadRelyingParty( - 'incorporations', - authenticate, - afterAuthRoute, - cancelRoute - ) - ); - } - ); - } else { - let self = this; - this.setState( - { - loading: false, - addingDocuments: false, - applicationId: null, - rpName: null - }, - async () => { - // Get current application info from kyc - let currentApplication = self.props.rp.applications.find(app => { - return app.id === id; - }); - // get stored application from local database - let application = this.props.applications.find(app => { - return app.id === id; - }); - const { - template, - vendor, - privacyPolicy, - termsOfService, - attributes - } = currentApplication; - const { rpName, title } = application; - /* eslint-disable camelcase */ - const description = application.sub_title; - /* eslint-enable camelcase */ - const agreement = true; - - // Set application data - await self.props.dispatch( - kycActions.setCurrentApplication( - rpName, - template, - afterAuthRoute, - cancelRoute, - title, - description, - agreement, - vendor, - privacyPolicy, - termsOfService, - attributes - ) - ); - - // Open add documents modal - // (Later on, we will need to improve this to be able to distinguish requirements - // that can be fulfilled by the wallet and ones that need redirect to KYCC.) - // - // await self.props.dispatch( - // kycOperations.loadRelyingParty( - // rpName, - // true, - // `/main/kyc/current-application/${rpName}?applicationId=${id}` - // ) - // ); - - // Redirects to KYCC chain on an external browser window with auto-login - const instanceUrl = self.props.rp.session.ctx.config.rootEndpoint; - const url = `${instanceUrl}/applications/${application.id}?access_token=${ - self.props.rp.session.access_token.jwt - }`; - window.openExternal(null, url); - } + async loadRelyingParties(vendors) { + const authenticated = true; + const { afterAuthRoute, cancelRoute } = this.props; + + for (const vendor of vendors) { + await this.props.dispatch( + kycOperations.loadRelyingParty( + vendor.vendorId, + authenticated, + afterAuthRoute, + cancelRoute + ) ); } + } + + handleApplicationAdditionalRequirements = application => { + const { rps } = this.props; + + // get current application info from RP + const rp = rps[application.rpName]; + if (!rp) { + console.warning(`Can't find RP named ${application.rpName}`); + return false; + } + // Later on, we will need to improve this to be able to distinguish requirements + // that can be fulfilled by the wallet directly and ones that need redirect to KYCC + // onboarding app. + // Redirects to KYCC with auto-login via JWT token + const instanceUrl = rp.session.ctx.config.rootEndpoint; + const url = `${instanceUrl}/applications/${application.id}?access_token=${ + rp.session.access_token.jwt + }`; + window.openExternal(null, url); }; - handleApplicationRefresh = id => { - const { afterAuthRoute } = this.props; - const cancelRoute = `/main/selfkeyId`; - const authenticate = true; - - // if relying party not loaded, try again - if (!this.state.refreshing) { - this.setState({ loading: true, refreshing: true, applicationId: id }, async () => { - await this.props.dispatch( - kycOperations.loadRelyingParty( - 'incorporations', - authenticate, - afterAuthRoute, - cancelRoute - ) - ); - }); - } else { - // get stored application from local database - let application = this.props.applications.find(app => { - return app.id === id; - }); - // get current application info from kyc - let kycApplication = this.props.rp.applications.find(app => { - return app.id === id; - }); - - if (application && kycApplication) { - // update stored application - application.currentStatus = kycApplication.currentStatus; - application.currentStatusName = kycApplication.statusName; - application.updatedAt = kycApplication.updatedAt; - } - - // sync of RP applications with local database is done automatically, all done, show modal - this.setState({ - refreshing: false, - applicationId: null, - showApplicationRefreshModal: true - }); + handleApplicationRefresh = application => { + const { rps } = this.props; + + // get current application info from RP + const rp = rps[application.rpName]; + if (!rp) { + console.warning(`Can't find RP named ${application.rpName}`); + return false; + } + + console.log(rp); + + const kycApplication = rp.applications.find(app => app.id === application.id); + + if (application && kycApplication) { + // update stored application + application.currentStatus = kycApplication.currentStatus; + application.currentStatusName = kycApplication.statusName; + application.updatedAt = kycApplication.updatedAt; } + + // sync of RP applications with local database is done automatically, all done, show modal + this.setState({ + showApplicationRefreshModal: true + }); }; handleCloseApplicationRefreshModal = evt => { @@ -212,41 +99,36 @@ class SelfkeyIdApplicationsContainerComponent extends Component { }; render() { - const { isLoading, processing } = this.props; - let loading = isLoading || processing || this.state.loading; + const { rps, vendors } = this.props; + const loading = Object.keys(rps).length === 0 || vendors.length === 0; return ( ); } } const mapStateToProps = (state, props) => { - const notAuthenticated = false; const walletType = appSelectors.selectApp(state).walletType; - const afterAuthRoute = - walletType === 'ledger' || walletType === 'trezor' ? `/main/selfkeyIdApplications` : ''; + return { wallet: walletSelectors.getWallet(state), - isLoading: incorporationsSelectors.getLoading(state), - rp: kycSelectors.relyingPartySelector(state, 'incorporations'), - rpShouldUpdate: kycSelectors.relyingPartyShouldUpdateSelector( - state, - 'incorporations', - notAuthenticated - ), + orders: marketplaceSelectors.getAllOrders(state), + vendors: marketplaceSelectors.selectActiveVendors(state), + rps: kycSelectors.relyingPartiesSelector(state), applications: kycSelectors.selectApplications(state), - processing: kycSelectors.selectProcessing(state), - afterAuthRoute + afterAuthRoute: + walletType === 'ledger' || walletType === 'trezor' ? `/main/selfkeyIdApplications` : '', + cancelRoute: `/main/selfkeyId` }; }; + export const SelfkeyIdApplicationsContainer = connect(mapStateToProps)( SelfkeyIdApplicationsContainerComponent ); diff --git a/src/renderer/selfkey-id/main/containers/selfkey-id.js b/src/renderer/selfkey-id/main/containers/selfkey-id.js index 590ac1749..b216af2f3 100644 --- a/src/renderer/selfkey-id/main/containers/selfkey-id.js +++ b/src/renderer/selfkey-id/main/containers/selfkey-id.js @@ -26,9 +26,7 @@ class SelfkeyIdContainerComponent extends Component { this.setState({ tab: tab ? parseInt(tab) : 0 }); } - handleTabChange = (event, tab) => { - this.setState({ tab }); - }; + handleTabChange = (event, tab) => this.setState({ tab }); componentDidUpdate() { if (this.props.identity.type !== 'individual') { @@ -37,6 +35,7 @@ class SelfkeyIdContainerComponent extends Component { } handleMarketplaceAccessClick = _ => this.props.dispatch(push(MARKETPLACE_ROOT_PATH)); + render() { const { tab } = this.state; let component = ( From 6b62252c44078d50361e7865678e10c87ed23815 Mon Sep 17 00:00:00 2001 From: Maxim Kovalov Date: Thu, 26 Sep 2019 15:38:40 +0300 Subject: [PATCH 156/207] feat(did): refactor out did redux --- src/common/did/index.js | 188 ++++++++++++++++++ src/common/store/configure-store.js | 2 + src/common/wallet/actions.js | 12 +- src/common/wallet/operations.js | 113 +---------- src/common/wallet/reducers.js | 13 +- src/common/wallet/selectors.js | 8 - src/common/wallet/tests.js | 0 src/common/wallet/types.js | 19 +- src/renderer/did/associate-did-container.js | 13 +- .../did/create-did-popup-container.jsx | 6 +- .../did/create-did-processing-container.jsx | 4 +- .../did/register-did-card-container.js | 10 +- .../categories/categories-page.jsx | 4 +- .../selfkey-did-required-container.jsx | 6 +- 14 files changed, 214 insertions(+), 184 deletions(-) create mode 100644 src/common/did/index.js delete mode 100644 src/common/wallet/tests.js diff --git a/src/common/did/index.js b/src/common/did/index.js new file mode 100644 index 000000000..2c0d7c0b1 --- /dev/null +++ b/src/common/did/index.js @@ -0,0 +1,188 @@ +import { identitySelectors, identityOperations } from '../identity'; +import { push } from 'connected-react-router'; +import { createAliasedAction } from 'electron-redux'; +import { appSelectors } from '../app'; +import { walletSelectors } from '../wallet'; +import { getGlobalContext } from 'common/context'; + +const hardwalletConfirmationTime = 30000; + +export const initialState = { + associateError: null, + originUrl: null, + pending: {} +}; + +export const didTypes = { + DID_CREATE: 'did/CREATE', + DID_UPDATE: 'did/UPDATE', + DID_ASSOCIATE_ERROR_SET: 'did/associate/SET', + DID_ORIGIN_URL_SET: 'did/origin_url/SET', + DID_PENDING_SET: 'did/pending/SET', + DID_CREATE_FLOW_START: 'did/flow/create/START', + DID_ASSOCIATE_FLOW_START: 'did/flow/associate/START' +}; + +export const didActions = { + setOriginUrlAction: url => ({ + type: didTypes.DID_ORIGIN_URL_SET, + payload: url + }), + setAssociateError: error => ({ + type: didTypes.DID_ASSOCIATE_ERROR_SET, + payload: error + }), + setDidPending: (identityId, isPending) => ({ + type: didTypes.DID_PENDING_SET, + payload: { identityId, isPending } + }) +}; + +export const didSelectors = { + selectDIDTree: state => state.did, + selectOriginUrl: state => didSelectors.selectDIDTree(state).originUrl, + selectAssociateError: state => didSelectors.selectDIDTree(state).associateError, + isPending: (state, identityId) => !!didSelectors.selectDIDTree(state).pending[identityId], + isCurrentIdentityPending: state => { + const identity = identitySelectors.selectCurrentIdentity(state); + return didSelectors.isPending(state, identity.id); + } +}; + +const createDIDOperation = () => async (dispatch, getState) => { + const walletFromStore = walletSelectors.getWallet(getState()); + let identity = identitySelectors.selectCurrentIdentity(getState()); + const didOriginUrl = didSelectors.selectOriginUrl(getState()); + try { + let hardwalletConfirmationTimeout = null; + const walletType = appSelectors.selectWalletType(getState()); + if (walletType === 'ledger' || walletType === 'trezor') { + await dispatch(push('/main/hd-transaction-timer')); + hardwalletConfirmationTimeout = setTimeout(async () => { + clearTimeout(hardwalletConfirmationTimeout); + await dispatch(push('/main/transaction-timeout')); + }, hardwalletConfirmationTime); + } + + const didService = getGlobalContext().didService; + await dispatch(didActions.setDidPending(identity.id, true)); + const gasLimit = await didService.getGasLimit(walletFromStore.publicKey); + const transaction = didService.createDID(walletFromStore.publicKey, gasLimit); + transaction.on('receipt', async receipt => { + const did = receipt.events.CreatedDID.returnValues.id; + const identityService = getGlobalContext().identityService; + identity = await identityService.updateIdentityDID(did, identity.id); + + await dispatch(didActions.setDidPending(identity.id, false)); + + await dispatch(identityOperations.updateIdentity(identity)); + await dispatch(push(didOriginUrl)); + }); + transaction.on('transactionHash', async hash => { + clearTimeout(hardwalletConfirmationTimeout); + await dispatch(push('/main/create-did-processing')); + }); + transaction.on('error', async error => { + clearTimeout(hardwalletConfirmationTimeout); + const message = error.toString().toLowerCase(); + if (message.indexOf('insufficient funds') !== -1) { + await dispatch(push('/main/transaction-no-gas-error')); + } else if (error.statusText === 'CONDITIONS_OF_USE_NOT_SATISFIED') { + await dispatch(push('/main/transaction-declined/Ledger')); + } else if (error.code === 'Failure_ActionCancelled') { + await dispatch(push('/main/transaction-declined/Trezor')); + } else if (error.statusText === 'UNKNOWN_ERROR') { + await dispatch(push('/main/transaction-unlock')); + } else { + await dispatch(push('/main/transaction-error')); + } + await dispatch(didActions.setDidPending(identity.id, false)); + console.error(error); + }); + } catch (error) { + await dispatch(didActions.setDidPending(identity.id, false)); + console.error(error); + } +}; + +const startCreateDidFlowOperation = didOriginUrl => async (dispatch, getState) => { + await dispatch(didActions.setOriginUrlAction(didOriginUrl)); + await dispatch(push('/main/get-did')); +}; + +const startAssociateDidFlowOperation = didOriginUrl => async (dispatch, getState) => { + await dispatch(didActions.setOriginUrlAction(didOriginUrl)); + await dispatch(push('/main/enter-did')); +}; + +const updateDIDOperation = did => async (dispatch, getState) => { + try { + const walletFromStore = walletSelectors.getWallet(getState()); + let identity = identitySelectors.selectCurrentIdentity(getState()); + const DIDService = getGlobalContext().didService; + const controllerAddress = await DIDService.getControllerAddress(did); + if (walletFromStore.publicKey.toLowerCase() === controllerAddress.toLowerCase()) { + const identityService = getGlobalContext().identityService; + identity = await identityService.updateIdentityDID(did, identity.id); + await dispatch(identityOperations.updateIdentity(identity)); + await dispatch(didActions.setAssociateError('none')); + } else { + await dispatch( + didActions.setAssociateError( + 'The DID provided is not derived from the current wallet.' + ) + ); + } + } catch (error) { + console.error(error); + await dispatch(didActions.setAssociateError('Invalid DID')); + } +}; + +const resetAssociateDIDOperation = () => async dispatch => { + await dispatch(didActions.setAssociateError('')); +}; + +export const didOperations = { + createDIDOperation: createAliasedAction(didTypes.DID_CREATE, createDIDOperation), + startCreateDidFlowOperation: createAliasedAction( + didTypes.DID_CREATE_FLOW_START, + startCreateDidFlowOperation + ), + startAssociateDidFlowOperation: createAliasedAction( + didTypes.DID_ASSOCIATE_FLOW_START, + startAssociateDidFlowOperation + ), + updateDIDOperation: createAliasedAction(didTypes.DID_UPDATE, updateDIDOperation), + resetAssociateDIDOperation +}; + +export const didReducers = { + setDidPendingReducer: (state, action) => { + const { identityId, isPending } = action.payload; + const pending = { ...state.pending, [identityId]: isPending }; + return { ...state, pending }; + }, + setAssociateErrorReducer: (state, action) => { + const associateError = action.payload; + return { ...state, associateError }; + }, + setOriginUrlReducer: (state, action) => { + const originUrl = action.payload; + return { ...state, originUrl }; + } +}; + +export const reducer = (state = initialState, action) => { + switch (action.type) { + case didTypes.DID_ORIGIN_URL_SET: + return didReducers.setOriginUrlReducer(state, action); + case didTypes.DID_PENDING_SET: + return didReducers.setDidPendingReducer(state, action); + case didTypes.DID_ASSOCIATE_ERROR_SET: + return didReducers.setAssociateErrorReducer(state, action); + } + return state; +}; + +export default reducer; diff --git a/src/common/store/configure-store.js b/src/common/store/configure-store.js index 24d56f2f0..a87a332bc 100644 --- a/src/common/store/configure-store.js +++ b/src/common/store/configure-store.js @@ -22,6 +22,7 @@ import identity from '../identity'; import { connectRouter, routerMiddleware } from 'connected-react-router'; import history from './history'; import createWallet from '../create-wallet'; +import did from '../did'; import transactionHistory from '../transaction-history'; import app from '../app'; import gas from '../gas'; @@ -86,6 +87,7 @@ export default (initialState, scope = 'main') => { kyc, tokens, scheduler, + did, ...scopedReducers }); const enhancer = compose(...enhanced); diff --git a/src/common/wallet/actions.js b/src/common/wallet/actions.js index 65b3ddea5..149cd5447 100644 --- a/src/common/wallet/actions.js +++ b/src/common/wallet/actions.js @@ -6,14 +6,4 @@ const updateWallet = createAliasedAction(types.WALLET_UPDATE, wallet => ({ payload: wallet })); -const setAssociateError = error => ({ - type: types.WALLET_ASSOCIATE_DID_ERROR_SET, - payload: error -}); - -const setDidOriginUrl = didOriginUrl => ({ - type: types.WALLET_DID_ORIGIN_URL_SET, - payload: didOriginUrl -}); - -export { updateWallet, setAssociateError, setDidOriginUrl }; +export { updateWallet }; diff --git a/src/common/wallet/operations.js b/src/common/wallet/operations.js index 8ec2e1acb..7ea47e727 100644 --- a/src/common/wallet/operations.js +++ b/src/common/wallet/operations.js @@ -1,13 +1,9 @@ import * as actions from './actions'; -import { getWallet, getDidOriginUrl } from './selectors'; -import { identitySelectors, identityOperations } from '../identity'; +import { getWallet } from './selectors'; import { getGlobalContext } from 'common/context'; import * as types from './types'; import { createAliasedAction } from 'electron-redux'; -import { push } from 'connected-react-router'; -import { appSelectors } from 'common/app'; -const hardwalletConfirmationTime = '30000'; const getWalletWithBalance = async wallet => { const walletService = getGlobalContext().walletService; @@ -27,10 +23,6 @@ const refreshWalletBalance = () => async (dispatch, getState) => { await dispatch(actions.updateWallet(await getWalletWithBalance(getWallet(getState())))); }; -const resetAssociateDID = () => async dispatch => { - await dispatch(actions.setAssociateError('')); -}; - const updateWalletName = (name, walletId) => async (dispatch, getState) => { try { const walletService = getGlobalContext().walletService; @@ -42,99 +34,6 @@ const updateWalletName = (name, walletId) => async (dispatch, getState) => { } }; -const createWalletDID = () => async (dispatch, getState) => { - const walletFromStore = getWallet(getState()); - let identity = identitySelectors.selectCurrentIdentity(getState()); - const didOriginUrl = getDidOriginUrl(getState()); - try { - let hardwalletConfirmationTimeout = null; - const walletType = appSelectors.selectWalletType(getState()); - if (walletType === 'ledger' || walletType === 'trezor') { - await dispatch(push('/main/hd-transaction-timer')); - hardwalletConfirmationTimeout = setTimeout(async () => { - clearTimeout(hardwalletConfirmationTimeout); - await dispatch(push('/main/transaction-timeout')); - }, hardwalletConfirmationTime); - } - - const didService = getGlobalContext().didService; - await dispatch(updateWalletWithBalance({ ...walletFromStore, didPending: true })); - const gasLimit = await didService.getGasLimit(walletFromStore.publicKey); - const transaction = didService.createDID(walletFromStore.publicKey, gasLimit); - transaction.on('receipt', async receipt => { - const did = receipt.events.CreatedDID.returnValues.id; - const identityService = getGlobalContext().identityService; - identity = await identityService.updateIdentityDID(did, identity.id); - await dispatch( - updateWalletWithBalance({ - ...walletFromStore, - didPending: false - }) - ); - await dispatch(identityOperations.updateIdentity(identity)); - await dispatch(push(didOriginUrl)); - }); - transaction.on('transactionHash', async hash => { - clearTimeout(hardwalletConfirmationTimeout); - await dispatch(push('/main/create-did-processing')); - }); - transaction.on('error', async error => { - clearTimeout(hardwalletConfirmationTimeout); - const message = error.toString().toLowerCase(); - if (message.indexOf('insufficient funds') !== -1) { - await dispatch(push('/main/transaction-no-gas-error')); - } else if (error.statusText === 'CONDITIONS_OF_USE_NOT_SATISFIED') { - await dispatch(push('/main/transaction-declined/Ledger')); - } else if (error.code === 'Failure_ActionCancelled') { - await dispatch(push('/main/transaction-declined/Trezor')); - } else if (error.statusText === 'UNKNOWN_ERROR') { - await dispatch(push('/main/transaction-unlock')); - } else { - await dispatch(push('/main/transaction-error')); - } - await dispatch(updateWalletWithBalance({ ...walletFromStore, didPending: false })); - console.error(error); - }); - } catch (error) { - await dispatch(updateWalletWithBalance({ ...walletFromStore, didPending: false })); - console.error(error); - } -}; - -const startCreateDidFlow = didOriginUrl => async (dispatch, getState) => { - await dispatch(actions.setDidOriginUrl(didOriginUrl)); - await dispatch(push('/main/get-did')); -}; - -const startAssociateDidFlow = didOriginUrl => async (dispatch, getState) => { - await dispatch(actions.setDidOriginUrl(didOriginUrl)); - await dispatch(push('/main/enter-did')); -}; - -const updateWalletDID = (walletId, did) => async (dispatch, getState) => { - try { - const walletFromStore = getWallet(getState()); - let identity = identitySelectors.selectCurrentIdentity(getState()); - const DIDService = getGlobalContext().didService; - const controllerAddress = await DIDService.getControllerAddress(did); - if (walletFromStore.publicKey.toLowerCase() === controllerAddress.toLowerCase()) { - const identityService = getGlobalContext().identityService; - identity = await identityService.updateIdentityDID(did, identity.id); - await dispatch(identityOperations.updateIdentity(identity)); - await dispatch(actions.setAssociateError('none')); - } else { - await dispatch( - actions.setAssociateError( - 'The DID provided is not derived from the current wallet.' - ) - ); - } - } catch (error) { - console.error(error); - await dispatch(actions.setAssociateError('Invalid DID')); - } -}; - const updateWalletSetup = (setup, walletId) => async (dispatch, getState) => { try { const walletService = getGlobalContext().walletService; @@ -152,14 +51,6 @@ export default { ...actions, updateWalletWithBalance, refreshWalletBalance, - resetAssociateDID, updateWalletName: createAliasedAction(types.WALLET_NAME_UPDATE, updateWalletName), - updateWalletSetup: createAliasedAction(types.WALLET_SETUP_UPDATE, updateWalletSetup), - createWalletDID: createAliasedAction(types.WALLET_DID_CREATE, createWalletDID), - updateWalletDID: createAliasedAction(types.WALLET_DID_UPDATE, updateWalletDID), - startCreateDidFlow: createAliasedAction(types.WALLET_START_DID_FLOW, startCreateDidFlow), - startAssociateDidFlow: createAliasedAction( - types.WALLET_START_ASSOCIATE_DID_FLOW, - startAssociateDidFlow - ) + updateWalletSetup: createAliasedAction(types.WALLET_SETUP_UPDATE, updateWalletSetup) }; diff --git a/src/common/wallet/reducers.js b/src/common/wallet/reducers.js index 1275336c6..6a50f0bb2 100644 --- a/src/common/wallet/reducers.js +++ b/src/common/wallet/reducers.js @@ -1,8 +1,7 @@ import * as types from './types'; const initialState = { - wallet: {}, - associateError: '' + wallet: {} }; const walletReducer = (state = initialState, action) => { @@ -12,16 +11,6 @@ const walletReducer = (state = initialState, action) => { ...state, ...action.payload }; - case types.WALLET_ASSOCIATE_DID_ERROR_SET: - return { - ...state, - associateError: action.payload - }; - case types.WALLET_DID_ORIGIN_URL_SET: - return { - ...state, - didOriginUrl: action.payload - }; default: return state; } diff --git a/src/common/wallet/selectors.js b/src/common/wallet/selectors.js index 48839086c..c5c0392f8 100644 --- a/src/common/wallet/selectors.js +++ b/src/common/wallet/selectors.js @@ -14,11 +14,3 @@ export const getWallet = state => { wallet.isHardwareWallet = wallet.profile === 'ledger' || wallet.profile === 'trezor'; return wallet; }; - -export const getAssociateError = state => { - return state.wallet.associateError; -}; - -export const getDidOriginUrl = state => { - return state.wallet.didOriginUrl; -}; diff --git a/src/common/wallet/tests.js b/src/common/wallet/tests.js deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/common/wallet/types.js b/src/common/wallet/types.js index 8239e330c..e9c576258 100644 --- a/src/common/wallet/types.js +++ b/src/common/wallet/types.js @@ -3,22 +3,5 @@ const WALLET_UPDATE = 'app/wallet/UPDATE'; const WALLET_AVATAR_UPDATE = 'app/wallet/avatar/UPDATE'; const WALLET_NAME_UPDATE = 'app/wallet/name/UPDATE'; const WALLET_SETUP_UPDATE = 'app/wallet/setup/UPDATE'; -const WALLET_DID_CREATE = 'app/wallet/did/CREATE'; -const WALLET_DID_UPDATE = 'app/wallet/did/UPDATE'; -const WALLET_ASSOCIATE_DID_ERROR_SET = 'app/wallet/did/ASSOCIATE/ERROR'; -const WALLET_DID_ORIGIN_URL_SET = 'app/wallet/did/ORIGIN_Url/SET'; -const WALLET_START_DID_FLOW = 'app/wallet/CREATE_DID_FLOW/START'; -const WALLET_START_ASSOCIATE_DID_FLOW = 'app/wallet/ASSOCIATE_DID_FLOW/START'; -export { - WALLET_UPDATE, - WALLET_AVATAR_UPDATE, - WALLET_NAME_UPDATE, - WALLET_SETUP_UPDATE, - WALLET_DID_CREATE, - WALLET_DID_UPDATE, - WALLET_ASSOCIATE_DID_ERROR_SET, - WALLET_DID_ORIGIN_URL_SET, - WALLET_START_DID_FLOW, - WALLET_START_ASSOCIATE_DID_FLOW -}; +export { WALLET_UPDATE, WALLET_AVATAR_UPDATE, WALLET_NAME_UPDATE, WALLET_SETUP_UPDATE }; diff --git a/src/renderer/did/associate-did-container.js b/src/renderer/did/associate-did-container.js index ac5047856..5480a72c7 100644 --- a/src/renderer/did/associate-did-container.js +++ b/src/renderer/did/associate-did-container.js @@ -1,9 +1,8 @@ import React, { Component } from 'react'; import { push } from 'connected-react-router'; import { connect } from 'react-redux'; -import { walletOperations, walletSelectors } from 'common/wallet'; import { identitySelectors } from 'common/identity'; - +import { didSelectors, didOperations } from 'common/did'; import { AssociateDid } from './associate-did'; class AssociateDIDContainerComponent extends Component { @@ -28,7 +27,7 @@ class AssociateDIDContainerComponent extends Component { } resetErrors = () => { - this.props.dispatch(walletOperations.resetAssociateDID()); + this.props.dispatch(didOperations.resetAssociateDIDOperation()); }; handleCancelClick = evt => { @@ -46,9 +45,7 @@ class AssociateDIDContainerComponent extends Component { await this.resetErrors(); let did = this.state.did; if (did !== '') { - await this.props.dispatch( - walletOperations.updateWalletDID(this.props.identity.walletId, did) - ); + await this.props.dispatch(didOperations.updateDIDOperation(did)); } else { this.setState({ searching: false }); } @@ -80,8 +77,8 @@ class AssociateDIDContainerComponent extends Component { const mapStateToProps = (state, props) => { return { identity: identitySelectors.selectCurrentIdentity(state), - associateError: walletSelectors.getAssociateError(state), - didOriginUrl: walletSelectors.getDidOriginUrl(state) + associateError: didSelectors.selectAssociateError(state), + didOriginUrl: didSelectors.selectOriginUrl(state) }; }; diff --git a/src/renderer/did/create-did-popup-container.jsx b/src/renderer/did/create-did-popup-container.jsx index e328bfe38..cc8b84f46 100644 --- a/src/renderer/did/create-did-popup-container.jsx +++ b/src/renderer/did/create-did-popup-container.jsx @@ -10,7 +10,7 @@ import { pricesSelectors } from 'common/prices'; import { ethGasStationInfoSelectors, ethGasStationInfoOperations } from 'common/eth-gas-station'; import { appOperations, appSelectors } from 'common/app'; import { gasSelectors, gasOperations } from 'common/gas'; -import { walletOperations, walletSelectors } from 'common/wallet'; +import { didSelectors, didOperations } from 'common/did'; import EthUnits from 'common/utils/eth-units'; import { push } from 'connected-react-router'; @@ -44,7 +44,7 @@ class CreateDIDPopupContainerComponent extends Component { handleCreateDIDAction = async _ => { await this.props.dispatch(appOperations.setGoBackPath('/main/get-did')); - await this.props.dispatch(walletOperations.createWalletDID()); + await this.props.dispatch(didOperations.createDIDOperation()); if (this.props.walletType === 'ledger' || this.props.walletType === 'trezor') { await this.props.dispatch(appOperations.setGoNextPath('/main/hd-transaction-timer')); } @@ -86,7 +86,7 @@ const mapStateToProps = (state, props) => { ...getFiatCurrency(state), walletType: appSelectors.selectWalletType(state), gasLimit: gasSelectors.selectGas(state).didGasLimit, - didOriginUrl: walletSelectors.getDidOriginUrl(state) + didOriginUrl: didSelectors.selectOriginUrl(state) }; }; diff --git a/src/renderer/did/create-did-processing-container.jsx b/src/renderer/did/create-did-processing-container.jsx index 79ce3be8d..3bddf96a9 100644 --- a/src/renderer/did/create-did-processing-container.jsx +++ b/src/renderer/did/create-did-processing-container.jsx @@ -2,7 +2,7 @@ import React, { Component } from 'react'; import { connect } from 'react-redux'; import { push } from 'connected-react-router'; import { TransactionProcessingPopup } from '../common/transaction-processing-popup'; -import { walletSelectors } from 'common/wallet'; +import { didSelectors } from 'common/did'; class CreateDIDProcessingContainerComponent extends Component { handleCloseAction = _ => { @@ -22,7 +22,7 @@ class CreateDIDProcessingContainerComponent extends Component { } const mapStateToProps = (state, props) => { - return { didOriginUrl: walletSelectors.getDidOriginUrl(state) }; + return { didOriginUrl: didSelectors.selectOriginUrl(state) }; }; export const CreateDIDProcessingContainer = connect(mapStateToProps)( diff --git a/src/renderer/did/register-did-card-container.js b/src/renderer/did/register-did-card-container.js index f5922aa62..943480d42 100644 --- a/src/renderer/did/register-did-card-container.js +++ b/src/renderer/did/register-did-card-container.js @@ -1,20 +1,20 @@ import React, { Component } from 'react'; import { connect } from 'react-redux'; import { RegisterDidCard } from './register-did-card'; -import { walletOperations, walletSelectors } from 'common/wallet'; +import { didOperations, didSelectors } from 'common/did'; const SELFKEY_ID_PATH = '/main/selfkeyId'; class RegisterDidCardContainerComponent extends Component { handleRegisterDidClick = _ => - this.props.dispatch(walletOperations.startCreateDidFlow(SELFKEY_ID_PATH)); + this.props.dispatch(didOperations.startCreateDidFlowOperation(SELFKEY_ID_PATH)); handleAssociateDidClick = _ => - this.props.dispatch(walletOperations.startAssociateDidFlow(SELFKEY_ID_PATH)); + this.props.dispatch(didOperations.startAssociateDidFlowOperation(SELFKEY_ID_PATH)); render() { return ( @@ -23,7 +23,7 @@ class RegisterDidCardContainerComponent extends Component { } export const RegisterDidCardContainer = connect(state => ({ - wallet: walletSelectors.getWallet(state) + pending: didSelectors.isCurrentIdentityPending(state) }))(RegisterDidCardContainerComponent); export default RegisterDidCardContainer; diff --git a/src/renderer/marketplace/categories/categories-page.jsx b/src/renderer/marketplace/categories/categories-page.jsx index a874c61f3..26a94a219 100644 --- a/src/renderer/marketplace/categories/categories-page.jsx +++ b/src/renderer/marketplace/categories/categories-page.jsx @@ -1,7 +1,7 @@ import React, { Component } from 'react'; import { connect } from 'react-redux'; import { ethGasStationInfoOperations } from 'common/eth-gas-station'; -import { marketplacesOperations, marketplacesSelectors } from 'common/marketplaces'; +import { marketplacesSelectors } from 'common/marketplaces'; import { MarketplaceCategoriesList } from './categories-list'; import { push } from 'connected-react-router'; import { ordersOperations } from '../../../common/marketplace/orders'; @@ -13,8 +13,6 @@ const mapStateToProps = state => ({ class MarketplaceCategoriesPageComponent extends Component { componentDidMount() { this.props.dispatch(ethGasStationInfoOperations.loadData()); - this.props.dispatch(marketplacesOperations.loadTransactions()); - this.props.dispatch(marketplacesOperations.loadStakes()); this.props.dispatch(ordersOperations.ordersLoadOperation()); } diff --git a/src/renderer/marketplace/selfkey-did-required-container.jsx b/src/renderer/marketplace/selfkey-did-required-container.jsx index d09e66a4d..32f2621b0 100644 --- a/src/renderer/marketplace/selfkey-did-required-container.jsx +++ b/src/renderer/marketplace/selfkey-did-required-container.jsx @@ -2,21 +2,21 @@ import React, { Component } from 'react'; import { connect } from 'react-redux'; import { push } from 'connected-react-router'; import { MarketplaceDIDRequired } from './selfkey-did-required'; -import { walletOperations } from 'common/wallet'; +import { didOperations } from 'common/did'; const MARKETPLACE_PATH = '/main/marketplace-categories'; class MarketplaceSelfkeyDIDRequiredContainer extends Component { handleConfirm = evt => { evt.preventDefault(); - this.props.dispatch(walletOperations.startCreateDidFlow(MARKETPLACE_PATH)); + this.props.dispatch(didOperations.startCreateDidFlowOperation(MARKETPLACE_PATH)); }; handleClose = () => { this.props.dispatch(push(MARKETPLACE_PATH)); }; handleEnterDID = evt => { evt.preventDefault(); - this.props.dispatch(walletOperations.startAssociateDidFlow(MARKETPLACE_PATH)); + this.props.dispatch(didOperations.startAssociateDidFlowOperation(MARKETPLACE_PATH)); }; render() { return ( From f0def4efc72c76ae01eeaa2c199145e3d3529faa Mon Sep 17 00:00:00 2001 From: Andre Goncalves Date: Thu, 26 Sep 2019 13:45:20 +0100 Subject: [PATCH 157/207] refactor: handle additional requirements --- .../selfkey-id/main/components/selfkey-id-applications.jsx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/renderer/selfkey-id/main/components/selfkey-id-applications.jsx b/src/renderer/selfkey-id/main/components/selfkey-id-applications.jsx index 1d174faaf..0b44797f0 100644 --- a/src/renderer/selfkey-id/main/components/selfkey-id-applications.jsx +++ b/src/renderer/selfkey-id/main/components/selfkey-id-applications.jsx @@ -404,10 +404,7 @@ class SelfkeyIdApplicationsComponent extends Component { application={item} status={item.currentStatus} onClick={() => - this.props.onApplicationAdditionalRequirements( - item.id, - item.rpName - ) + this.props.onApplicationAdditionalRequirements(item) } handleRefresh={() => this.props.onApplicationRefresh(item)} tooltip={moment(new Date(item.updatedAt)).format( From a8b563c6ff133caef4613356c253dc1f1264164f Mon Sep 17 00:00:00 2001 From: Maxim Kovalov Date: Thu, 26 Sep 2019 17:11:51 +0300 Subject: [PATCH 158/207] feat(address): wallet publicKey -> address --- .storybook/store-data.json | 4 +- src/common/address-book/operations.js | 2 +- src/common/address-book/operations.spec.js | 2 +- src/common/app/index.js | 4 +- src/common/eth-gas-station/operations.spec.js | 2 +- src/common/exchanges/selectors.spec.js | 2 +- src/common/gas/index.js | 2 +- src/common/marketplace/orders/index.js | 8 +-- src/common/transaction-history/index.js | 4 +- src/common/transaction/operations.js | 10 +-- src/common/transaction/operations.spec.js | 8 +-- src/common/wallet-tokens/operations.js | 4 +- src/common/wallet/operations.js | 6 +- src/main/blockchain/tx-history-service.js | 8 +-- src/main/blockchain/tx-history.js | 32 ++++----- src/main/blockchain/web3-service.js | 2 +- src/main/blockchain/web3-service.spec.js | 8 +-- .../data-updaters/balance-updater-service.js | 2 +- src/main/lws/login-attempt.spec.js | 2 +- src/main/lws/lws-service.js | 20 +++--- src/main/lws/lws-service.spec.js | 42 ++++++------ src/main/marketplace/marketplace-service.js | 4 +- .../marketplace/marketplace-service.spec.js | 2 +- .../20190926162553_wallet-address.js | 41 +++++++++++ src/main/platform/identity.js | 2 +- src/main/platform/identity.spec.js | 12 ++-- src/main/rpc-handler.js | 68 ++++++++----------- src/main/wallet/wallet-service.js | 36 +++++----- src/main/wallet/wallet.js | 19 ++---- src/main/wallet/wallet.spec.js | 33 ++------- src/renderer/dashboard/token-box.jsx | 10 +-- .../checkout/checkout-container.jsx | 2 +- .../checkout/payment-complete-container.jsx | 2 +- .../checkout/payment-container.jsx | 2 +- .../select-bank/select-bank-container.jsx | 2 +- .../incorporations-checkout-container.jsx | 2 +- ...orporations-payment-complete-container.jsx | 2 +- .../incorporations-payment-container.jsx | 2 +- .../common/transaction-error-box.jsx | 8 +-- src/renderer/transaction/receive/index.jsx | 12 ++-- src/renderer/transaction/send/index.jsx | 8 +-- .../components/transaction-declined.jsx | 4 +- .../containers/transaction-declined.js | 2 +- .../components/transaction-error.jsx | 28 ++++---- .../containers/transaction-error.js | 2 +- .../components/transaction-no-gas-error.jsx | 4 +- .../containers/transaction-no-gas-error.js | 2 +- .../components/transaction-no-key-error.jsx | 4 +- .../containers/transaction-no-key-error.js | 2 +- .../transactions-history/index.jsx | 4 +- src/renderer/wallet/create/backup-address.jsx | 6 +- src/renderer/wallet/main/index.jsx | 4 +- .../wallet/unlock/existing-address.jsx | 4 +- test/e2e/address-book/common-steps.js | 6 +- .../marketplace/bank-accounts/common-step.js | 10 +-- 55 files changed, 260 insertions(+), 265 deletions(-) create mode 100644 src/main/migrations/20190926162553_wallet-address.js diff --git a/.storybook/store-data.json b/.storybook/store-data.json index af7d10205..c746a12cd 100644 --- a/.storybook/store-data.json +++ b/.storybook/store-data.json @@ -14,7 +14,7 @@ "path": null, "profile": "local", "profilePicture": null, - "publicKey": "0xBBc024B6bC7885EC486F6586A25b465Ec59Ede1d", + "address": "0xBBc024B6bC7885EC486F6586A25b465Ec59Ede1d", "updatedAt": 1568104786548 }, "walletTokens": { @@ -27395,7 +27395,7 @@ "privateKey": null, "profile": "local", "profilePicture": null, - "publicKey": "0xbbc024b6bc7885ec486f6586a25b465ec59ede1d", + "address": "0xbbc024b6bc7885ec486f6586a25b465ec59ede1d", "updatedAt": 1568104786548 } ], diff --git a/src/common/address-book/operations.js b/src/common/address-book/operations.js index e153e48af..f4db720dc 100644 --- a/src/common/address-book/operations.js +++ b/src/common/address-book/operations.js @@ -59,7 +59,7 @@ const validateAddress = address => async (dispatch, getState) => { 'addressBookService' in context ? context.addressBookService.isValidAddress(address) : EthUtils.isValidAddress(address); - const currentWalletAddress = walletSelectors.getWallet(getState()).publicKey; + const currentWalletAddress = walletSelectors.getWallet(getState()).address; const existentAddress = getAddresses(getState()).filter(entry => { return entry.address === address; }); diff --git a/src/common/address-book/operations.spec.js b/src/common/address-book/operations.spec.js index 195ee8d0c..fdad861f2 100644 --- a/src/common/address-book/operations.spec.js +++ b/src/common/address-book/operations.spec.js @@ -179,7 +179,7 @@ describe('address book operations', () => { isValidAddress() {} }; const wallet = { - publicKey: '0xdasdas' + address: '0xdasdas' }; const entries = [ diff --git a/src/common/app/index.js b/src/common/app/index.js index 2281b1ac1..24f14a03f 100644 --- a/src/common/app/index.js +++ b/src/common/app/index.js @@ -185,11 +185,11 @@ const unlockWalletWithPrivateKey = privateKey => async dispatch => { } }; -const unlockWalletWithPublicKey = (publicKey, path) => async (dispatch, getState) => { +const unlockWalletWithPublicKey = (address, path) => async (dispatch, getState) => { const walletService = getGlobalContext().walletService; const walletType = selectApp(getState()).walletType; try { - const wallet = await walletService.unlockWalletWithPublicKey(publicKey, path, walletType); + const wallet = await walletService.unlockWalletWithPublicKey(address, path, walletType); await dispatch(appOperations.unlockWalletOperation(wallet)); await dispatch(push('/main/dashboard')); } catch (error) { diff --git a/src/common/eth-gas-station/operations.spec.js b/src/common/eth-gas-station/operations.spec.js index 0aa895bee..936b857a6 100644 --- a/src/common/eth-gas-station/operations.spec.js +++ b/src/common/eth-gas-station/operations.spec.js @@ -18,7 +18,7 @@ describe('operations', () => { address: '' }, wallet: { - publicKey: 'dasdsa' + address: 'dasdsa' }, ethGasStationInfo: { ethGasStationInfo: { diff --git a/src/common/exchanges/selectors.spec.js b/src/common/exchanges/selectors.spec.js index 43b984316..de6229e5e 100644 --- a/src/common/exchanges/selectors.spec.js +++ b/src/common/exchanges/selectors.spec.js @@ -99,7 +99,7 @@ describe('selectors', () => { price: 210.32, privateKey: 'fdsfdsfdsfds4231321dasdf21ed3', profile: 'local', - publicKey: '4184288c556524df9cb9e58b73265ee66dca4efe', + address: '4184288c556524df9cb9e58b73265ee66dca4efe', symbol: 'ETH' }; diff --git a/src/common/gas/index.js b/src/common/gas/index.js index 08fb5364b..d0662184c 100644 --- a/src/common/gas/index.js +++ b/src/common/gas/index.js @@ -25,7 +25,7 @@ const loadDIDGasLimit = () => async (dispatch, getState) => { const wallet = walletSelectors.getWallet(getState()); try { const didService = getGlobalContext().didService; - const gasLimit = await didService.getGasLimit(wallet.publicKey); + const gasLimit = await didService.getGasLimit(wallet.address); await dispatch(gasActions.setDIDGasLimitAction(gasLimit)); } catch (e) { log.error(e); diff --git a/src/common/marketplace/orders/index.js b/src/common/marketplace/orders/index.js index 37d5a54ea..9d65534a2 100644 --- a/src/common/marketplace/orders/index.js +++ b/src/common/marketplace/orders/index.js @@ -227,7 +227,7 @@ const checkOrderAllowanceOperation = orderId => async (dispatch, getState) => { const amount = ordersSelectors.getContractFormattedAmount(getState(), orderId); let allowance = await selfkeyService.getAllowance( - wallet.publicKey, + wallet.address, config.paymentSplitterAddress ); let update = null; @@ -309,7 +309,7 @@ const preapproveCurrentOrderOperation = () => async (dispatch, getState) => { const amount = ordersSelectors.getContractFormattedAmount(getState(), orderId); const receipt = await selfkeyService.approve( - wallet.publicKey, + wallet.address, config.paymentSplitterAddress, amount, allowanceGas, @@ -448,7 +448,7 @@ const payCurrentOrderOperation = () => async (dispatch, getState) => { try { const amount = ordersSelectors.getContractFormattedAmount(getState(), orderId); const receipt = await paymentService.makePayment( - wallet.publicKey, + wallet.address, order.did, order.vendorDID, amount, @@ -502,7 +502,7 @@ const estimateCurrentPreapproveGasOperation = () => async (dispatch, getState) = const wallet = walletSelectors.getWallet(getState()); const amount = ordersSelectors.getContractFormattedAmount(getState(), orderId); const gasLimit = await getGlobalContext().selfkeyService.estimateApproveGasLimit( - wallet.publicKey, + wallet.address, config.paymentSplitterAddress, amount ); diff --git a/src/common/transaction-history/index.js b/src/common/transaction-history/index.js index 448ab6503..6c704e8fb 100644 --- a/src/common/transaction-history/index.js +++ b/src/common/transaction-history/index.js @@ -28,7 +28,7 @@ const transactionHistoryActions = { const loadTransactions = () => async (dispatch, getState) => { const wallet = walletSelectors.getWallet(getState()); const txHistoryService = getGlobalContext().txHistoryService; - const transactions = await txHistoryService.getTransactions(wallet.publicKey); + const transactions = await txHistoryService.getTransactions(wallet.address); await dispatch(transactionHistoryActions.setTransactionsAction(transactions)); }; @@ -38,7 +38,7 @@ const reloadTransactions = () => async (dispatch, getState) => { await dispatch(transactionHistoryActions.setProcessingAction(true)); await txHistoryService.reload(wallet); await dispatch(transactionHistoryActions.setProcessingAction(false)); - const transactions = await txHistoryService.getTransactions(wallet.publicKey); + const transactions = await txHistoryService.getTransactions(wallet.address); await dispatch(transactionHistoryActions.setTransactionsAction(transactions)); }; diff --git a/src/common/transaction/operations.js b/src/common/transaction/operations.js index 319a87835..ed86265f6 100644 --- a/src/common/transaction/operations.js +++ b/src/common/transaction/operations.js @@ -81,10 +81,10 @@ export const getGasLimit = async ( return tokenService.getGasLimit(tokenContract, address, amount, walletAddress); }; -const getTransactionCount = async publicKey => { +const getTransactionCount = async address => { const params = { method: 'getTransactionCount', - args: [publicKey, 'pending'] + args: [address, 'pending'] }; return (getGlobalContext() || {}).web3Service.waitForTicket(params); @@ -99,7 +99,7 @@ export const setTransactionFee = (newAddress, newAmount, newGasPrice, newGasLimi const transaction = getTransaction(state); const address = !newAddress ? transaction.address : newAddress; const amount = !newAmount ? transaction.amount : newAmount; - const walletAddress = state.wallet.publicKey; + const walletAddress = state.wallet.address; dispatch(setLocked(true)); @@ -422,7 +422,7 @@ const updateBalances = () => async (dispatch, getState) => { let tokens = getTokens(getState()).splice(1); await dispatch(walletOperations.updateWalletWithBalance(wallet)); - await dispatch(walletTokensOperations.updateWalletTokensWithBalance(tokens, wallet.publicKey)); + await dispatch(walletTokensOperations.updateWalletTokensWithBalance(tokens, wallet.address)); await dispatch( actions.updateTransaction({ @@ -440,7 +440,7 @@ const createTxHistry = transactionHash => (dispatch, getState) => { ...transaction, tokenSymbol, networkId: chainId, - from: wallet.publicKey, + from: wallet.address, to: transaction.address, value: +transaction.amount, gasPrice: +transaction.gasPrice, diff --git a/src/common/transaction/operations.spec.js b/src/common/transaction/operations.spec.js index e98089e81..b01abf5ac 100644 --- a/src/common/transaction/operations.spec.js +++ b/src/common/transaction/operations.spec.js @@ -53,7 +53,7 @@ const getStoreMock = (transaction = {}) => ] }, wallet: { - publicKey: 'dasdsa' + address: 'dasdsa' }, walletTokens: { tokens: [] @@ -320,7 +320,7 @@ describe('operations', () => { cryptoCurrency: undefined }, wallet: { - publicKey: 'dasdsa' + address: 'dasdsa' }, ethGasStationInfo: { ethGasStationInfo: { @@ -375,7 +375,7 @@ describe('operations', () => { cryptoCurrency: undefined }, wallet: { - publicKey: 'dasdsa' + address: 'dasdsa' }, ethGasStationInfo: { ethGasStationInfo: { @@ -430,7 +430,7 @@ describe('operations', () => { cryptoCurrency: undefined }, wallet: { - publicKey: 'dasdsa' + address: 'dasdsa' }, ethGasStationInfo: { ethGasStationInfo: { diff --git a/src/common/wallet-tokens/operations.js b/src/common/wallet-tokens/operations.js index 837fdafc1..1375fce84 100644 --- a/src/common/wallet-tokens/operations.js +++ b/src/common/wallet-tokens/operations.js @@ -11,7 +11,7 @@ const loadWalletTokens = createAliasedAction( const walletTokenService = getGlobalContext().walletTokenService; const wallet = getWallet(getState()); const tokens = await walletTokenService.getWalletTokens(wallet.id); - await dispatch(updateWalletTokensWithBalance(tokens, wallet.publicKey)); + await dispatch(updateWalletTokensWithBalance(tokens, wallet.address)); } ); @@ -47,7 +47,7 @@ const refreshWalletTokensBalance = () => async (dispatch, getState) => { const state = getState(); await dispatch( actions.setWalletTokens( - await getWalletTokensWithBalance(getTokens(state), getWallet(state).publicKey) + await getWalletTokensWithBalance(getTokens(state), getWallet(state).address) ) ); }; diff --git a/src/common/wallet/operations.js b/src/common/wallet/operations.js index 8ec2e1acb..efa0e3f13 100644 --- a/src/common/wallet/operations.js +++ b/src/common/wallet/operations.js @@ -59,8 +59,8 @@ const createWalletDID = () => async (dispatch, getState) => { const didService = getGlobalContext().didService; await dispatch(updateWalletWithBalance({ ...walletFromStore, didPending: true })); - const gasLimit = await didService.getGasLimit(walletFromStore.publicKey); - const transaction = didService.createDID(walletFromStore.publicKey, gasLimit); + const gasLimit = await didService.getGasLimit(walletFromStore.address); + const transaction = didService.createDID(walletFromStore.address, gasLimit); transaction.on('receipt', async receipt => { const did = receipt.events.CreatedDID.returnValues.id; const identityService = getGlobalContext().identityService; @@ -117,7 +117,7 @@ const updateWalletDID = (walletId, did) => async (dispatch, getState) => { let identity = identitySelectors.selectCurrentIdentity(getState()); const DIDService = getGlobalContext().didService; const controllerAddress = await DIDService.getControllerAddress(did); - if (walletFromStore.publicKey.toLowerCase() === controllerAddress.toLowerCase()) { + if (walletFromStore.address.toLowerCase() === controllerAddress.toLowerCase()) { const identityService = getGlobalContext().identityService; identity = await identityService.updateIdentityDID(did, identity.id); await dispatch(identityOperations.updateIdentity(identity)); diff --git a/src/main/blockchain/tx-history-service.js b/src/main/blockchain/tx-history-service.js index 1e43117c5..9553d1e6d 100644 --- a/src/main/blockchain/tx-history-service.js +++ b/src/main/blockchain/tx-history-service.js @@ -309,7 +309,7 @@ export class TxHistoryService { async sync() { let wallets = await Wallet.findAll(); for (let wallet of wallets) { - let address = wallet.publicKey.toLowerCase(); + let address = wallet.address.toLowerCase(); address = address.startsWith('0x') ? address : `0x${address}`; await this.syncByWallet(address, wallet.id); await this.removeNotMinedPendingTxs(address); @@ -334,12 +334,12 @@ export class TxHistoryService { })(); } - async getTransactions(publicKey) { - return TxHistory.findByPublicKey(publicKey); + async getTransactions(address) { + return TxHistory.findByPublicKey(address); } async reload(wallet) { - let address = wallet.publicKey.toLowerCase(); + let address = wallet.address.toLowerCase(); address = address.startsWith('0x') ? address : `0x${address}`; await this.syncByWallet(address, wallet.id, true, true); await this.removeNotMinedPendingTxs(address); diff --git a/src/main/blockchain/tx-history.js b/src/main/blockchain/tx-history.js index e94501122..5d2a48cfe 100644 --- a/src/main/blockchain/tx-history.js +++ b/src/main/blockchain/tx-history.js @@ -96,28 +96,28 @@ export class TxHistory extends BaseModel { return this.query().insertAndFetch(data); } - static findByPublicKey(publicKey) { - publicKey = publicKey.toLowerCase(); + static findByPublicKey(address) { + address = address.toLowerCase(); return this.query() - .where({ from: publicKey }) - .orWhere({ to: publicKey }) + .where({ from: address }) + .orWhere({ to: address }) .orderBy('timeStamp', 'desc'); } - static findByPublicKeyAndTokenSymbol(publicKey, tokenSymbol, pager) { - publicKey = publicKey.toLowerCase(); + static findByPublicKeyAndTokenSymbol(address, tokenSymbol, pager) { + address = address.toLowerCase(); let query = this.query() - .where({ from: publicKey, tokenSymbol }) - .orWhere({ to: publicKey, tokenSymbol }) + .where({ from: address, tokenSymbol }) + .orWhere({ to: address, tokenSymbol }) .orderBy('timeStamp', 'desc'); return paginator(this.knex())(query, pager); } - static findByPublicKeyAndContractAddress(publicKey, contractAddress, pager) { - publicKey = publicKey.toLowerCase(); + static findByPublicKeyAndContractAddress(address, contractAddress, pager) { + address = address.toLowerCase(); let query = this.query() - .where({ from: publicKey, contractAddress }) - .orWhere({ to: publicKey, contractAddress }) + .where({ from: address, contractAddress }) + .orWhere({ to: address, contractAddress }) .orderBy('timeStamp', 'desc'); return paginator(this.knex())(query, pager); } @@ -137,15 +137,15 @@ export class TxHistory extends BaseModel { /** * Find pending transactions and get updated information from the blockchain * - * @param {string} publicKey + * @param {string} address * @return {Promise} */ - static async updatePendingTxsByPublicKey(publicKey) { - publicKey = publicKey.toLowerCase(); + static async updatePendingTxsByPublicKey(address) { + address = address.toLowerCase(); const query = await this.query() .whereNull('blockNumber') .andWhere(function() { - this.where({ from: publicKey }).orWhere({ to: publicKey }); + this.where({ from: address }).orWhere({ to: address }); }); await Promise.all(query.map(this.syncTx.bind(this))); diff --git a/src/main/blockchain/web3-service.js b/src/main/blockchain/web3-service.js index 9eb890df0..21938b98c 100644 --- a/src/main/blockchain/web3-service.js +++ b/src/main/blockchain/web3-service.js @@ -277,7 +277,7 @@ export class Web3Service { if (!wallet) { wallet = this.store.getState().wallet; } - if (!wallet || wallet.publicKey !== opts.from) { + if (!wallet || wallet.address !== opts.from) { throw new Error('provided wallet does not contain requested address'); } if ((wallet.profile && wallet.profile !== 'local') || wallet.isHardwareWallet) { diff --git a/src/main/blockchain/web3-service.spec.js b/src/main/blockchain/web3-service.spec.js index 26417e840..6851f1393 100644 --- a/src/main/blockchain/web3-service.spec.js +++ b/src/main/blockchain/web3-service.spec.js @@ -115,9 +115,9 @@ describe('Web3Service', () => { encodeABI: sinon.stub(), estimateGas: sinon.stub().resolves(100) }; - let wallet = { publicKey: '0xtest', privateKey: 'test', profile: 'local' }; + let wallet = { address: '0xtest', privateKey: 'test', profile: 'local' }; store.state.wallet = wallet; - const args = { from: wallet.publicKey }; + const args = { from: wallet.address }; sinon.stub(ethMock, 'sendSignedTransaction').resolves('ok'); service.web3.eth = ethMock; service.web3.utils = ethUtilMock; @@ -132,9 +132,9 @@ describe('Web3Service', () => { }); it('uses regular send method for non local profiles', async () => { let contactMethodInstance = { send: sinon.stub() }; - let wallet = { publicKey: '0xtest', privateKey: 'test', profile: 'test' }; + let wallet = { address: '0xtest', privateKey: 'test', profile: 'test' }; store.state.wallet = wallet; - const args = { from: wallet.publicKey }; + const args = { from: wallet.address }; await service.sendSignedTransaction(contactMethodInstance, contractAddress, [args]); expect(contactMethodInstance.send.calledOnceWith(args)).toBeTruthy(); store.state.wallet = {}; diff --git a/src/main/data-updaters/balance-updater-service.js b/src/main/data-updaters/balance-updater-service.js index 7db1658ab..aec2c1a89 100644 --- a/src/main/data-updaters/balance-updater-service.js +++ b/src/main/data-updaters/balance-updater-service.js @@ -22,7 +22,7 @@ export class BalanceUpdaterService extends EventEmitter { updateTokensBalance() { let tokens = this.getCurrentWalletTokens(); let wallet = this.getCurrentWallet(); - return store.dispatch(walletTokensOperations.updateWalletTokens(tokens, wallet.publicKey)); + return store.dispatch(walletTokensOperations.updateWalletTokens(tokens, wallet.address)); } getCurrentWallet() { diff --git a/src/main/lws/login-attempt.spec.js b/src/main/lws/login-attempt.spec.js index 889b06c8b..b2b673ae0 100644 --- a/src/main/lws/login-attempt.spec.js +++ b/src/main/lws/login-attempt.spec.js @@ -13,7 +13,7 @@ describe('LoginAttempt', () => { errorMessage: 'A test error has occured', signup: true }; - const testWallet = { id: 10, publicKey: 'public' }; + const testWallet = { id: 10, address: 'public' }; beforeEach(async () => { await TestDb.init(); }); diff --git a/src/main/lws/lws-service.js b/src/main/lws/lws-service.js index f8b7c0abb..f980d8f0d 100644 --- a/src/main/lws/lws-service.js +++ b/src/main/lws/lws-service.js @@ -42,11 +42,11 @@ export class LWSService { let payload = await Wallet.findAll().eager('identities'); payload = await Promise.all( payload.map(async w => { - const identity = conn.getIdentity(w.publicKey); + const identity = conn.getIdentity(w.address); let unlocked = !!identity; let signedUp = unlocked && (await w.hasSignedUpTo(website.url)); const retWallet = { - publicKey: w.publicKey, + publicKey: w.address, unlocked, profile: w.profile, name: w.name, @@ -73,11 +73,11 @@ export class LWSService { getHardwareWalletsPayload(wallets, conn, website, type) { return Promise.all( wallets.map(async w => { - let unlocked = !!conn.getIdentity(w.publicKey); - const wallet = Wallet.findByPublicKey(w.publicKey); + let unlocked = !!conn.getIdentity(w.address); + const wallet = Wallet.findByPublicKey(w.address); let signedUp = unlocked && wallet && (await wallet.hasSignedUpTo(website.url)); return { - publicKey: w.publicKey, + publicKey: w.address, unlocked, profile: type, signedUp @@ -183,7 +183,7 @@ export class LWSService { log.debug('XXX reqUnlock ident %2j', ident); wallet = !wallet ? await Wallet.create({ - publicKey, + address: publicKey, profile, path }) @@ -556,12 +556,12 @@ export class WSConnection { }; } - addIdentity(publicKey, identity) { - this.ctx.identities[publicKey] = identity; + addIdentity(address, identity) { + this.ctx.identities[address] = identity; } - getIdentity(publicKey) { - return this.ctx.identities[publicKey] || null; + getIdentity(address) { + return this.ctx.identities[address] || null; } async handleMessage(msg) { diff --git a/src/main/lws/lws-service.spec.js b/src/main/lws/lws-service.spec.js index e4afad6df..1adfe7893 100644 --- a/src/main/lws/lws-service.spec.js +++ b/src/main/lws/lws-service.spec.js @@ -10,14 +10,14 @@ jest.mock('node-fetch'); describe('lws-service', () => { const connMock = wallet => ({ - getIdentity(publicKey) { - if (publicKey === wallet.publicKey) { + getIdentity(address) { + if (address === wallet.address) { return wallet; } return null; }, send(msg, req) {}, - addIdentity(publicKey, identity) {} + addIdentity(address, identity) {} }); const identity = { id: 1, @@ -42,7 +42,7 @@ describe('lws-service', () => { eager: () => [ { name: 'test1', - publicKey: 'unlocked', + address: 'unlocked', profile: 'local', hasSignedUpTo() { return true; @@ -50,7 +50,7 @@ describe('lws-service', () => { }, { name: 'test2', - publicKey: 'locked', + address: 'locked', profile: 'local', hasSignedUpTo() { return true; @@ -60,7 +60,7 @@ describe('lws-service', () => { }); const conn = connMock({ - publicKey: 'unlocked', + address: 'unlocked', privateKey: 'private', ident: { isSetupFinished: false } }); @@ -101,17 +101,17 @@ describe('lws-service', () => { getLedgerWallets: () => {} }; setGlobalContext({ walletService }); - sinon.stub(walletService, 'getLedgerWallets').returns([{ publicKey: 'test' }]); + sinon.stub(walletService, 'getLedgerWallets').returns([{ address: 'test' }]); sinon.stub(Wallet, 'findByPublicKey'); Wallet.findByPublicKey.resolves({ - publicKey: 'test', + address: 'test', profile: 'ledger', hasSignedUpTo() { return false; } }); - const conn = connMock({ publicKey: 'unlocked', privateKey: 'private' }); + const conn = connMock({ address: 'unlocked', privateKey: 'private' }); sinon.stub(conn, 'send'); const msg = { @@ -143,17 +143,17 @@ describe('lws-service', () => { getTrezorWallets: () => {} }; setGlobalContext({ walletService }); - sinon.stub(walletService, 'getTrezorWallets').returns([{ publicKey: 'test' }]); + sinon.stub(walletService, 'getTrezorWallets').returns([{ address: 'test' }]); sinon.stub(Wallet, 'findByPublicKey'); Wallet.findByPublicKey.resolves({ - publicKey: 'test', + address: 'test', profile: 'trezor', hasSignedUpTo() { return false; } }); - const conn = connMock({ publicKey: 'unlocked', privateKey: 'private' }); + const conn = connMock({ address: 'unlocked', privateKey: 'private' }); sinon.stub(conn, 'send'); const msg = { @@ -210,7 +210,7 @@ describe('lws-service', () => { await service.reqUnlock( { payload: { - publicKey: wallet.publicKey, + publicKey: wallet.address, config: { website: { url: 'test' } }, profile } @@ -226,14 +226,14 @@ describe('lws-service', () => { conn.send.calledWithMatch( { payload: { - publicKey: wallet.publicKey, + publicKey: wallet.address, profile: wallet.profile, unlocked: expected } }, { payload: { - publicKey: wallet.publicKey, + publicKey: wallet.address, config: { website: { url: 'test' } } } } @@ -508,7 +508,7 @@ describe('lws-service', () => { const identity = { getPublicKeyFromHardwareWallet: async () => 'test' }; const conn = { send: () => {}, - getIdentity: publicKey => identity + getIdentity: address => identity }; const msg = { payload: { publicKey: 'test', profile: 'ledger' } }; await service.reqAuth(msg, conn); @@ -589,7 +589,7 @@ describe('lws-service', () => { const identity = { getPublicKeyFromHardwareWallet: async () => 'test' }; const conn = { send: () => {}, - getIdentity: publicKey => identity + getIdentity: address => identity }; const msg = { payload: { publicKey: 'test', profile: 'ledger' } }; sinon.stub(conn, 'send'); @@ -709,12 +709,12 @@ describe('lws-service', () => { }); it('unlockWallet', () => { - const publicKey = 'public'; + const address = 'public'; const privateKey = 'private'; - expect(wsconn.getIdentity(publicKey)).toBeNull(); - wsconn.addIdentity(publicKey, privateKey); - expect(wsconn.getIdentity(publicKey)).toBe(privateKey); + expect(wsconn.getIdentity(address)).toBeNull(); + wsconn.addIdentity(address, privateKey); + expect(wsconn.getIdentity(address)).toBe(privateKey); }); describe('handleMessage', () => { it('sends error on invalalid json msg', async () => { diff --git a/src/main/marketplace/marketplace-service.js b/src/main/marketplace/marketplace-service.js index cbbdb2f8c..538bf007d 100644 --- a/src/main/marketplace/marketplace-service.js +++ b/src/main/marketplace/marketplace-service.js @@ -22,8 +22,8 @@ export class MarketplaceService { } get walletAddress() { - if (!this.wallet || !this.wallet.publicKey) return null; - return this.wallet.publicKey; + if (!this.wallet || !this.wallet.address) return null; + return this.wallet.address; } loadTransactions(serviceOwner, serviceId) { return MarketplaceTransactions.find({ serviceOwner, serviceId }); diff --git a/src/main/marketplace/marketplace-service.spec.js b/src/main/marketplace/marketplace-service.spec.js index 336e0928b..bbd9aad9d 100644 --- a/src/main/marketplace/marketplace-service.spec.js +++ b/src/main/marketplace/marketplace-service.spec.js @@ -12,7 +12,7 @@ describe('MarketplaceService', () => { placeStake() {}, withdrawStake() {} }; - let wallet = { publicKey: '0xtest', balance: 0 }; + let wallet = { address: '0xtest', balance: 0 }; let state = { wallet, prices: { prices: [] } }; let store = { dispatch: () => {}, diff --git a/src/main/migrations/20190926162553_wallet-address.js b/src/main/migrations/20190926162553_wallet-address.js new file mode 100644 index 000000000..c04b7601d --- /dev/null +++ b/src/main/migrations/20190926162553_wallet-address.js @@ -0,0 +1,41 @@ +/* istanbul ignore file */ +exports.up = async (knex, Promise) => { + try { + await knex.schema.renameTable('wallets', 'wallets_old'); + await knex.schema.createTable('wallets', table => { + table.increments('id'); + table.string('name'); + table + .string('address') + .unique() + .notNullable(); + table.string('keystoreFilePath'); + table + .string('profile') + .notNullable() + .defaultTo('local'); + table.string('path'); + table.integer('createdAt').notNullable(); + table.integer('updatedAt'); + }); + + let wallets = await knex('wallets_old').select(); + wallets = wallets.map(w => { + const newW = { ...w }; + newW.address = w.publicKey; + delete newW.publicKey; + delete newW.profilePicture; + delete newW.privateKey; + delete newW.isSetupFinished; + return newW; + }); + if (wallets.length) { + await knex('wallets').insert(wallets); + } + await knex.schema.dropTable('wallets_old'); + } catch (error) { + console.error(error); + } +}; + +exports.down = async (knex, Promise) => {}; diff --git a/src/main/platform/identity.js b/src/main/platform/identity.js index acf43f048..d8bb14a54 100644 --- a/src/main/platform/identity.js +++ b/src/main/platform/identity.js @@ -9,7 +9,7 @@ import AppEth from '@ledgerhq/hw-app-eth'; const log = new Logger('Identity'); export class Identity { constructor(wallet, ident) { - this.address = wallet.publicKey; + this.address = wallet.address; this.publicKey = null; this.profile = wallet.profile; this.privateKey = wallet.privateKey ? wallet.privateKey.replace('0x', '') : null; diff --git a/src/main/platform/identity.spec.js b/src/main/platform/identity.spec.js index 07038e62c..373a992df 100644 --- a/src/main/platform/identity.spec.js +++ b/src/main/platform/identity.spec.js @@ -7,13 +7,13 @@ jest.mock('../keystorage'); describe('identity', () => { let id = null; - const publicKey = '0x1Ff482D42D8727258A1686102Fa4ba925C46Bc42'; + const address = '0x1Ff482D42D8727258A1686102Fa4ba925C46Bc42'; const privateKey = 'c6cbd7d76bc5baca530c875663711b947efa6a86a900a9e8645ce32e5821484e'; const ident = {}; beforeEach(() => { id = new Identity( { - publicKey, + address, privateKey, profile: 'local', wid: 1 @@ -39,14 +39,14 @@ describe('identity', () => { }, ident ); - sinon.stub(id1, 'getPublicKeyFromHardwareWallet').returns(publicKey); + sinon.stub(id1, 'getPublicKeyFromHardwareWallet').returns(address); await id1.unlock(); - expect(id1.publicKey).toEqual(publicKey); + expect(id1.publicKey).toEqual(address); }); it('should throw invalid password if failed to unlock keystore', async () => { let id1 = new Identity( { - publicKey, + address, profile: 'local' }, ident @@ -64,7 +64,7 @@ describe('identity', () => { it('should unlock keystore', async () => { let id1 = new Identity( { - publicKey, + address, profile: 'local' }, ident diff --git a/src/main/rpc-handler.js b/src/main/rpc-handler.js index b0eb8f15d..efe205fe2 100644 --- a/src/main/rpc-handler.js +++ b/src/main/rpc-handler.js @@ -88,7 +88,7 @@ module.exports = function(cradle) { let keystoreFileName = path.basename(outputPath); let keystoreFilePath = path.join(keystoreObject.address, keystoreFileName); Wallet.create({ - publicKey: keystoreObject.address, + address: keystoreObject.address, keystoreFilePath: keystoreFilePath }) .then(resp => { @@ -97,7 +97,7 @@ module.exports = function(cradle) { const newWallet = { id: resp.id, isSetupFinished: resp.isSetupFinished, - publicKey: keystoreObject.address, + address: keystoreObject.address, privateKey: privateKey, keystoreFilePath: keystoreFilePath }; @@ -145,7 +145,7 @@ module.exports = function(cradle) { } Wallet.create({ - publicKey: keystoreObject.address, + address: keystoreObject.address, keystoreFilePath: ksFilePathToSave }) .then(resp => { @@ -153,7 +153,7 @@ module.exports = function(cradle) { const newWallet = { id: resp.id, isSetupFinished: resp.isSetupFinished, - publicKey: keystoreObject.address, + address: keystoreObject.address, privateKey: privateKey, keystoreFilePath: ksFilePathToSave, profile: 'local' @@ -207,7 +207,7 @@ module.exports = function(cradle) { // refactored controller.prototype.unlockKeystoreFile = function(event, actionId, actionName, args) { try { - let selectWalletPromise = Wallet.findByPublicKey(args.publicKey); + let selectWalletPromise = Wallet.findByPublicKey(args.address); selectWalletPromise .then(wallet => { let keystoreFileFullPath = path.join( @@ -223,7 +223,7 @@ module.exports = function(cradle) { id: wallet.id, isSetupFinished: wallet.isSetupFinished, privateKey: privateKey, - publicKey: keystoreObject.address, + address: keystoreObject.address, keystoreFilePath: wallet.keystoreFilePath, profile: wallet.profile }; @@ -259,11 +259,11 @@ module.exports = function(cradle) { // refactored controller.prototype.importPrivateKey = function(event, actionId, actionName, args) { try { - let publicKey = ethereumjsUtil.privateToAddress(args.privateKey); - publicKey = publicKey.toString('hex'); + let address = ethereumjsUtil.privateToAddress(args.privateKey); + address = address.toString('hex'); let privateKeyBuffer = Buffer.from(args.privateKey, 'hex'); - let walletSelectPromise = Wallet.findByPublicKey(publicKey); + let walletSelectPromise = Wallet.findByPublicKey(address); let profile = 'local'; walletSelectPromise @@ -275,13 +275,13 @@ module.exports = function(cradle) { } else { Wallet.create({ profile, - publicKey + address }) .then(resp => { const newWallet = { id: resp.id, isSetupFinished: resp.isSetupFinished, - publicKey: publicKey, + address: address, privateKey: privateKeyBuffer, profile }; @@ -334,7 +334,7 @@ module.exports = function(cradle) { try { keystorage.importFromFile(filePaths[0], keystoreObject => { app.win.webContents.send(RPC_METHOD, actionId, actionName, null, { - publicKey: keystoreObject.address, + address: keystoreObject.address, keystoreFilePath: filePaths[0] }); }); @@ -912,16 +912,6 @@ module.exports = function(cradle) { }); }; - controller.prototype.findActiveWallets = function(event, actionId, actionName, args) { - Wallet.findActive() - .then(data => { - app.win.webContents.send(RPC_METHOD, actionId, actionName, null, data); - }) - .catch(error => { - app.win.webContents.send(RPC_METHOD, actionId, actionName, error, null); - }); - }; - controller.prototype.findAllWalletsWithKeyStoreFile = function( event, actionId, @@ -939,7 +929,7 @@ module.exports = function(cradle) { controller.prototype.getWalletByPublicKey = async function(event, actionId, actionName, args) { try { - let data = await Wallet.findByPublicKey(args.publicKey); + let data = await Wallet.findByPublicKey(args.address); await store.dispatch(walletOperations.updateWalletWithBalance(data)); app.win.webContents.send(RPC_METHOD, actionId, actionName, null, data); @@ -982,7 +972,7 @@ module.exports = function(cradle) { Wallet.findById(data.walletId).then(wallet => { WalletToken.findByTokenId(data.tokenId).then(tokens => { store.dispatch( - walletTokensOperations.updateWalletTokensWithBalance(tokens, wallet.publicKey) + walletTokensOperations.updateWalletTokensWithBalance(tokens, wallet.address) ); }); }); @@ -1050,7 +1040,7 @@ module.exports = function(cradle) { store.dispatch( walletTokensOperations.updateWalletTokensWithBalance( data, - wallet.publicKey + wallet.address ) ); app.win.webContents.send(RPC_METHOD, actionId, actionName, null, data); @@ -1175,11 +1165,11 @@ module.exports = function(cradle) { controller.prototype.createHarwareWalletByAdress = function(event, actionId, actionName, args) { try { - let publicKey = args.address; + let address = args.address; let { profile } = args; - publicKey = publicKey.toString('hex'); + address = address.toString('hex'); - let walletSelectPromise = Wallet.findByPublicKey(publicKey); + let walletSelectPromise = Wallet.findByPublicKey(address); walletSelectPromise .then(wallet => { if (wallet) { @@ -1187,14 +1177,14 @@ module.exports = function(cradle) { app.win.webContents.send(RPC_METHOD, actionId, actionName, null, wallet); } else { Wallet.create({ - publicKey, + address, profile }) .then(resp => { const newWallet = { id: resp.id, isSetupFinished: resp.isSetupFinished, - publicKey, + address, profile }; store.dispatch(walletOperations.updateWalletWithBalance(newWallet)); @@ -1243,9 +1233,9 @@ module.exports = function(cradle) { actionName, args ) { - TxHistory.findByPublicKeyAndTokenSymbol(args.publicKey, args.tokenSymbol, args.pager) + TxHistory.findByPublicKeyAndTokenSymbol(args.address, args.tokenSymbol, args.pager) .then(data => { - data = { ...data, isSyncing: TxHistoryService.isSyncing(args.publicKey) }; + data = { ...data, isSyncing: TxHistoryService.isSyncing(args.address) }; app.win.webContents.send(RPC_METHOD, actionId, actionName, null, data); }) .catch(error => { @@ -1259,13 +1249,9 @@ module.exports = function(cradle) { actionName, args ) { - TxHistory.findByPublicKeyAndContractAddress( - args.publicKey, - args.contractAddress, - args.pager - ) + TxHistory.findByPublicKeyAndContractAddress(args.address, args.contractAddress, args.pager) .then(data => { - data = { ...data, isSyncing: TxHistoryService.isSyncing(args.publicKey) }; + data = { ...data, isSyncing: TxHistoryService.isSyncing(args.address) }; app.win.webContents.send(RPC_METHOD, actionId, actionName, null, data); }) .catch(error => { @@ -1275,7 +1261,7 @@ module.exports = function(cradle) { controller.prototype.syncTxHistoryByWallet = function(event, actionId, actionName, args) { txHistoryService - .syncByWallet(args.publicKey, args.walletId, args.showProgress) + .syncByWallet(args.address, args.walletId, args.showProgress) .then(data => { app.win.webContents.send(RPC_METHOD, actionId, actionName, null, data); }) @@ -1295,9 +1281,9 @@ module.exports = function(cradle) { }; controller.prototype.getTxHistoryByPublicKey = function(event, actionId, actionName, args) { - TxHistory.findByPublicKey(args.publicKey, args.pager) + TxHistory.findByPublicKey(args.address, args.pager) .then(data => { - data = { ...data, isSyncing: TxHistoryService.isSyncing(args.publicKey) }; + data = { ...data, isSyncing: TxHistoryService.isSyncing(args.address) }; app.win.webContents.send(RPC_METHOD, actionId, actionName, null, data); }) .catch(error => { diff --git a/src/main/wallet/wallet-service.js b/src/main/wallet/wallet-service.js index d3d899861..5d6224b57 100644 --- a/src/main/wallet/wallet-service.js +++ b/src/main/wallet/wallet-service.js @@ -47,7 +47,7 @@ export class WalletService { try { await fs.promises.copyFile( wallet.keystoreFilePath, - path.resolve(toPath, wallet.publicKey) + path.resolve(toPath, wallet.address) ); return true; } catch (error) { @@ -61,7 +61,7 @@ export class WalletService { this.web3Service.setDefaultAccount(account); const keystoreFileFullPath = await this.saveAccountToKeystore(account, password); const wallet = await Wallet.create({ - publicKey: account.address, + address: account.address, keystoreFilePath: keystoreFileFullPath, profile: 'local' }); @@ -76,7 +76,7 @@ export class WalletService { async getBalance(id) { const wallet = await Wallet.findById(id); - const balanceInWei = await this.web3Service.web3.eth.getBalance(wallet.publicKey); + const balanceInWei = await this.web3Service.web3.eth.getBalance(wallet.address); return EthUnits.toEther(balanceInWei, 'wei'); } @@ -89,7 +89,7 @@ export class WalletService { const account = await this.loadAccountFromKeystore( wallet.keystoreFilePath, password, - wallet.publicKey + wallet.address ); if (!account) { throw new Error('Wrong Password!'); @@ -97,7 +97,7 @@ export class WalletService { await this.web3Service.setDefaultAccount(account); return { ...wallet, - publicKey: account.address, + address: account.address, privateKey: account.privateKey }; } @@ -115,7 +115,7 @@ export class WalletService { if (!wallet) { wallet = await Wallet.create({ - publicKey: account.address, + address: account.address, keystoreFilePath: keystoreFileFullPath, profile: 'local' }); @@ -141,7 +141,7 @@ export class WalletService { if (!wallet) { wallet = await Wallet.create({ - publicKey: account.address, + address: account.address, profile: 'local' }); } @@ -153,13 +153,13 @@ export class WalletService { return newWallet; } - async unlockWalletWithPublicKey(publicKey, hwPath, profile) { - let wallet = await Wallet.findByPublicKey(publicKey); - this.web3Service.setDefaultAddress(publicKey); + async unlockWalletWithPublicKey(address, hwPath, profile) { + let wallet = await Wallet.findByPublicKey(address); + this.web3Service.setDefaultAddress(address); if (!wallet) { wallet = await Wallet.create({ - publicKey, + address, profile, path: hwPath }); @@ -232,32 +232,32 @@ export default WalletService; // const ctx = getGlobalContext(); // console.log('XXX', wallet); // let res = await ctx.selfkeyService.getAllowance( -// wallet.publicKey, +// wallet.address, // '0xb91FF8627f30494d27b91Aac1cB3c7465BE58fF5' // ); // const amount = 20000000000000; // let gas = await ctx.selfkeyService.estimateApproveGasLimit( -// wallet.publicKey, +// wallet.address, // '0xb91FF8627f30494d27b91Aac1cB3c7465BE58fF5', // amount // ); // console.log('XXX pre allow', res.toString()); // res = await ctx.selfkeyService.approve( -// wallet.publicKey, +// wallet.address, // '0xb91FF8627f30494d27b91Aac1cB3c7465BE58fF5', // amount, // gas // ); // console.log('XXX approve res', res.events.Approval.returnValues); // res = await ctx.selfkeyService.getAllowance( -// wallet.publicKey, +// wallet.address, // '0xb91FF8627f30494d27b91Aac1cB3c7465BE58fF5' // ); // console.log('XXX post approve', res.toString()); // const did = wallet.did; // // gas = await ctx.paymentService.getGasLimit( -// // wallet.publicKey, +// // wallet.address, // // did, // // did, // // 10000, @@ -268,7 +268,7 @@ export default WalletService; // // console.log('XXX payment gas', gas); // res = await ctx.paymentService.makePayment( -// wallet.publicKey, +// wallet.address, // did, // did, // 10000, @@ -280,7 +280,7 @@ export default WalletService; // console.log('XXX payment res', res); // res = await ctx.selfkeyService.getAllowance( -// wallet.publicKey, +// wallet.address, // '0xb91FF8627f30494d27b91Aac1cB3c7465BE58fF5' // ); // console.log('XXX post payment', res.toString()); diff --git a/src/main/wallet/wallet.js b/src/main/wallet/wallet.js index f1e7cb0d6..33dda54a1 100644 --- a/src/main/wallet/wallet.js +++ b/src/main/wallet/wallet.js @@ -20,10 +20,8 @@ export class Wallet extends BaseModel { properties: { id: { type: 'integer' }, name: { type: 'string' }, - publicKey: { type: 'string' }, - privateKey: { type: 'string' }, + address: { type: 'string' }, keystoreFilePath: { type: 'string' }, - isSetupFinished: { type: 'integer' }, profile: { type: 'string' }, path: { type: 'string' } } @@ -73,7 +71,7 @@ export class Wallet extends BaseModel { } static async create(itm) { - itm.publicKey = itm.publicKey.toLowerCase(); + itm.address = itm.address.toLowerCase(); const tx = await transaction.start(this.knex()); try { let insertedItm = await this.query(tx).insertGraphAndFetch( @@ -104,10 +102,6 @@ export class Wallet extends BaseModel { } } - static findActive() { - return this.findAllWithKeyStoreFile().where({ isSetupFinished: 1 }); - } - static findById(id) { return this.query().findById(id); } @@ -120,8 +114,8 @@ export class Wallet extends BaseModel { return this.query(); } - static findByPublicKey(publicKey) { - return this.query().findOne({ publicKey: publicKey.toLowerCase() }); + static findByPublicKey(address) { + return this.query().findOne({ address: address.toLowerCase() }); } static async updateName({ id, name }) { @@ -129,11 +123,6 @@ export class Wallet extends BaseModel { return wallet; } - static async updateSetup({ id, setup }) { - let wallet = await this.query().patchAndFetchById(id, { isSetupFinished: setup ? 1 : 0 }); - return wallet; - } - async hasSignedUpTo(websiteUrl) { let logins = await this.$relatedQuery('loginAttempts') .where({ diff --git a/src/main/wallet/wallet.spec.js b/src/main/wallet/wallet.spec.js index 016f7e230..7c1ec91e6 100644 --- a/src/main/wallet/wallet.spec.js +++ b/src/main/wallet/wallet.spec.js @@ -2,17 +2,15 @@ import Wallet from './wallet'; import TestDb from '../db/test-db'; describe('Wallet model', () => { - const testItm = { publicKey: 'abc', keystoreFilePath: 'abcd' }; + const testItm = { address: 'abc', keystoreFilePath: 'abcd' }; const testItm2 = { - publicKey: 'active', - keystoreFilePath: 'active keystore', - isSetupFinished: 1 + address: 'active', + keystoreFilePath: 'active keystore' }; const testItm3 = { - publicKey: 'public-key-1', - isSetupFinished: 1 + address: 'public-key-1' }; beforeEach(async () => { @@ -34,14 +32,6 @@ describe('Wallet model', () => { expect(setting.walletId).toBe(itm.id); }); - it('findActive', async () => { - await Wallet.query().insert(testItm); - await Wallet.query().insert(testItm2); - let found = await Wallet.findActive(); - expect(found.length).toBe(1); - expect(found[0].isSetupFinished).toBe(1); - }); - it('findAll', async () => { let found = await Wallet.findAll(); expect(found.length).toBe(0); @@ -64,19 +54,10 @@ describe('Wallet model', () => { it('findByPublicKey', async () => { await Wallet.query().insert(testItm); await Wallet.query().insert(testItm2); - let found = await Wallet.findByPublicKey(testItm.publicKey); + let found = await Wallet.findByPublicKey(testItm.address); expect(found).toMatchObject(testItm); }); - it('updateSetup', async () => { - let itm = await Wallet.query().insertAndFetch(testItm); - expect(itm.isSetupFinished).toEqual(0); - itm.setup = 1; - await Wallet.updateSetup(itm); - let check = await Wallet.query().findById(itm.id); - expect(check.isSetupFinished).toBe(itm.setup); - }); - it('updateName', async () => { let itm = await Wallet.query().insertAndFetch(testItm); expect(itm.name).toBeNull(); @@ -95,7 +76,7 @@ describe('Wallet model', () => { success: true, signup: true }; - const testWallet = { id: 10, publicKey: 'public' }; + const testWallet = { id: 10, address: 'public' }; let wallet = null; beforeEach(async () => { wallet = await Wallet.query().insertAndFetch(testWallet); @@ -155,7 +136,7 @@ describe('Wallet model', () => { success: true, signup: true }; - const testWallet = { id: 10, publicKey: 'public' }; + const testWallet = { id: 10, address: 'public' }; it('adds a new login attempt', async () => { let wallet = await Wallet.query().insertAndFetch(testWallet); await wallet.addLoginAttempt({ ...testLoginAttempt }); diff --git a/src/renderer/dashboard/token-box.jsx b/src/renderer/dashboard/token-box.jsx index dad028279..66f09c611 100644 --- a/src/renderer/dashboard/token-box.jsx +++ b/src/renderer/dashboard/token-box.jsx @@ -12,7 +12,7 @@ const styles = theme => ({ padding: 20, maxWidth: 350 }, - publicKey: { + address: { fontSize: 10.5 }, tokenBoxHeader: { @@ -37,7 +37,7 @@ const TokenBox = props => { CryptoCurrencyIconComponent, transferAction, children, - publicKey + address } = props; return ( @@ -69,11 +69,11 @@ const TokenBox = props => { variant="subtitle2" color="secondary" > - {publicKey} + {address} - + @@ -83,7 +83,7 @@ const TokenBox = props => { const mapStateToProps = state => { return { - publicKey: getWallet(state).publicKey + address: getWallet(state).address }; }; diff --git a/src/renderer/marketplace/bank-accounts/checkout/checkout-container.jsx b/src/renderer/marketplace/bank-accounts/checkout/checkout-container.jsx index 80def7514..93cb4ae24 100644 --- a/src/renderer/marketplace/bank-accounts/checkout/checkout-container.jsx +++ b/src/renderer/marketplace/bank-accounts/checkout/checkout-container.jsx @@ -124,7 +124,7 @@ const mapStateToProps = (state, props) => { ...getFiatCurrency(state), ...ethGasStationInfoSelectors.getEthGasStationInfo(state), tokens: getTokens(state).splice(1), // remove ETH - publicKey: getWallet(state).publicKey, + address: getWallet(state).address, keyRate: pricesSelectors.getRate(state, 'KEY', 'USD'), ethRate: pricesSelectors.getRate(state, 'ETH', 'USD'), cryptoCurrency: CRYPTOCURRENCY, diff --git a/src/renderer/marketplace/bank-accounts/checkout/payment-complete-container.jsx b/src/renderer/marketplace/bank-accounts/checkout/payment-complete-container.jsx index 6f955966d..875645cf7 100644 --- a/src/renderer/marketplace/bank-accounts/checkout/payment-complete-container.jsx +++ b/src/renderer/marketplace/bank-accounts/checkout/payment-complete-container.jsx @@ -89,7 +89,7 @@ const mapStateToProps = (state, props) => { return { jurisdiction: marketplaceSelectors.selectBankJurisdictionByAccountCode(state, accountCode), transaction: transactionSelectors.getTransaction(state), - publicKey: getWallet(state).publicKey, + address: getWallet(state).address, currentApplication: kycSelectors.selectCurrentApplication(state), rp: kycSelectors.relyingPartySelector(state, vendorId), rpShouldUpdate: kycSelectors.relyingPartyShouldUpdateSelector( diff --git a/src/renderer/marketplace/bank-accounts/checkout/payment-container.jsx b/src/renderer/marketplace/bank-accounts/checkout/payment-container.jsx index 3ee4cac99..2227a5e6c 100644 --- a/src/renderer/marketplace/bank-accounts/checkout/payment-container.jsx +++ b/src/renderer/marketplace/bank-accounts/checkout/payment-container.jsx @@ -61,7 +61,7 @@ const mapStateToProps = (state, props) => { vendorId, accountCode, jurisdiction: marketplaceSelectors.selectBankJurisdictionByAccountCode(state, accountCode), - publicKey: getWallet(state).publicKey, + address: getWallet(state).address, keyRate: pricesSelectors.getRate(state, 'KEY', 'USD'), currentApplication: kycSelectors.selectCurrentApplication(state), rp: kycSelectors.relyingPartySelector(state, vendorId), diff --git a/src/renderer/marketplace/bank-accounts/select-bank/select-bank-container.jsx b/src/renderer/marketplace/bank-accounts/select-bank/select-bank-container.jsx index b06cf01e8..b7643bc1a 100644 --- a/src/renderer/marketplace/bank-accounts/select-bank/select-bank-container.jsx +++ b/src/renderer/marketplace/bank-accounts/select-bank/select-bank-container.jsx @@ -78,7 +78,7 @@ const mapStateToProps = (state, props) => { countryCode, accountCode, jurisdiction: marketplaceSelectors.selectBankJurisdictionByAccountCode(state, accountCode), - publicKey: getWallet(state).publicKey, + address: getWallet(state).address, currentApplication: kycSelectors.selectCurrentApplication(state), rp: kycSelectors.relyingPartySelector(state, vendorId), rpShouldUpdate: kycSelectors.relyingPartyShouldUpdateSelector( diff --git a/src/renderer/marketplace/incorporation/checkout/incorporations-checkout-container.jsx b/src/renderer/marketplace/incorporation/checkout/incorporations-checkout-container.jsx index e474666aa..4af5fcf94 100644 --- a/src/renderer/marketplace/incorporation/checkout/incorporations-checkout-container.jsx +++ b/src/renderer/marketplace/incorporation/checkout/incorporations-checkout-container.jsx @@ -124,7 +124,7 @@ const mapStateToProps = (state, props) => { ...getFiatCurrency(state), ...ethGasStationInfoSelectors.getEthGasStationInfo(state), tokens: getTokens(state).splice(1), // remove ETH - publicKey: getWallet(state).publicKey, + address: getWallet(state).address, keyRate: pricesSelectors.getRate(state, 'KEY', 'USD'), ethRate: pricesSelectors.getRate(state, 'ETH', 'USD'), cryptoCurrency: CRYPTOCURRENCY, diff --git a/src/renderer/marketplace/incorporation/checkout/incorporations-payment-complete-container.jsx b/src/renderer/marketplace/incorporation/checkout/incorporations-payment-complete-container.jsx index 7e60890ca..c9e00236c 100644 --- a/src/renderer/marketplace/incorporation/checkout/incorporations-payment-complete-container.jsx +++ b/src/renderer/marketplace/incorporation/checkout/incorporations-payment-complete-container.jsx @@ -114,7 +114,7 @@ const mapStateToProps = (state, props) => { vendorId, program: incorporationsSelectors.getIncorporationsDetails(state, companyCode), transaction: transactionSelectors.getTransaction(state), - publicKey: getWallet(state).publicKey, + address: getWallet(state).address, currentApplication: kycSelectors.selectCurrentApplication(state), rp: kycSelectors.relyingPartySelector(state, vendorId), rpShouldUpdate: kycSelectors.relyingPartyShouldUpdateSelector( diff --git a/src/renderer/marketplace/incorporation/checkout/incorporations-payment-container.jsx b/src/renderer/marketplace/incorporation/checkout/incorporations-payment-container.jsx index 2768cea50..1f7172218 100644 --- a/src/renderer/marketplace/incorporation/checkout/incorporations-payment-container.jsx +++ b/src/renderer/marketplace/incorporation/checkout/incorporations-payment-container.jsx @@ -64,7 +64,7 @@ const mapStateToProps = (state, props) => { state, c => c.data.companyCode === companyCode ), - publicKey: getWallet(state).publicKey, + address: getWallet(state).address, keyRate: pricesSelectors.getRate(state, 'KEY', 'USD'), currentApplication: kycSelectors.selectCurrentApplication(state), rp: kycSelectors.relyingPartySelector(state, vendorId), diff --git a/src/renderer/transaction/common/transaction-error-box.jsx b/src/renderer/transaction/common/transaction-error-box.jsx index ae56241bc..c5d04630c 100644 --- a/src/renderer/transaction/common/transaction-error-box.jsx +++ b/src/renderer/transaction/common/transaction-error-box.jsx @@ -6,7 +6,7 @@ import Popup from '../../common/popup'; const styles = theme => ({}); export const TransactionErrorBox = withStyles(styles)( - ({ children, publicKey, closeAction, open = true, subtitle }) => ( + ({ children, address, closeAction, open = true, subtitle }) => ( @@ -16,16 +16,16 @@ export const TransactionErrorBox = withStyles(styles)( {subtitle} {children} - {publicKey && ( + {address && ( <> Your Address: - {publicKey} + {address} - + diff --git a/src/renderer/transaction/receive/index.jsx b/src/renderer/transaction/receive/index.jsx index 6ec9a12aa..2229ac400 100644 --- a/src/renderer/transaction/receive/index.jsx +++ b/src/renderer/transaction/receive/index.jsx @@ -159,8 +159,8 @@ const getIconForToken = token => { export class ReceiveTransfer extends React.Component { render() { - const { classes, cryptoCurrency, publicKey } = this.props; - let link = `mailto:?body=${publicKey}`; + const { classes, cryptoCurrency, address } = this.props; + let link = `mailto:?body=${address}`; let printDiv = () => { window.print(); @@ -192,7 +192,7 @@ export class ReceiveTransfer extends React.Component {
- +
- {publicKey} + {address}
@@ -235,7 +235,7 @@ export class Transfer extends React.Component { const mapStateToProps = state => { return { - publicKey: getWallet(state).publicKey, + address: getWallet(state).address, transactions: transactionHistorySelectors.selectTransactionHistory(state).transactions }; }; diff --git a/src/renderer/transaction/transaction-declined/components/transaction-declined.jsx b/src/renderer/transaction/transaction-declined/components/transaction-declined.jsx index 070d0c12d..db7a780ea 100644 --- a/src/renderer/transaction/transaction-declined/components/transaction-declined.jsx +++ b/src/renderer/transaction/transaction-declined/components/transaction-declined.jsx @@ -9,10 +9,10 @@ const styles = theme => ({ }); export const TransactionDeclined = withStyles(styles)( - ({ classes, publicKey, closeAction, match }) => { + ({ classes, address, closeAction, match }) => { return ( diff --git a/src/renderer/transaction/transaction-declined/containers/transaction-declined.js b/src/renderer/transaction/transaction-declined/containers/transaction-declined.js index c32e76f9d..f96062d31 100644 --- a/src/renderer/transaction/transaction-declined/containers/transaction-declined.js +++ b/src/renderer/transaction/transaction-declined/containers/transaction-declined.js @@ -23,7 +23,7 @@ class TransactionDeclinedContainer extends Component { const mapStateToProps = state => { return { - publicKey: getWallet(state).publicKey + address: getWallet(state).address }; }; diff --git a/src/renderer/transaction/transaction-error/components/transaction-error.jsx b/src/renderer/transaction/transaction-error/components/transaction-error.jsx index d8840fbc8..150034bc9 100644 --- a/src/renderer/transaction/transaction-error/components/transaction-error.jsx +++ b/src/renderer/transaction/transaction-error/components/transaction-error.jsx @@ -8,20 +8,18 @@ const styles = theme => ({ } }); -export const TransactionError = withStyles(styles)( - ({ classes, message, publicKey, closeAction }) => { - return ( - - - {message} - - - ); - } -); +export const TransactionError = withStyles(styles)(({ classes, message, address, closeAction }) => { + return ( + + + {message} + + + ); +}); export default TransactionError; diff --git a/src/renderer/transaction/transaction-error/containers/transaction-error.js b/src/renderer/transaction/transaction-error/containers/transaction-error.js index daaa44871..1c2db1581 100644 --- a/src/renderer/transaction/transaction-error/containers/transaction-error.js +++ b/src/renderer/transaction/transaction-error/containers/transaction-error.js @@ -23,7 +23,7 @@ class TransactionErrorContainer extends Component { const mapStateToProps = state => { return { - publicKey: getWallet(state).publicKey + address: getWallet(state).address }; }; diff --git a/src/renderer/transaction/transaction-no-gas-error/components/transaction-no-gas-error.jsx b/src/renderer/transaction/transaction-no-gas-error/components/transaction-no-gas-error.jsx index 933b90ca9..394dcd262 100644 --- a/src/renderer/transaction/transaction-no-gas-error/components/transaction-no-gas-error.jsx +++ b/src/renderer/transaction/transaction-no-gas-error/components/transaction-no-gas-error.jsx @@ -19,7 +19,7 @@ const styles = theme => ({ }); export const TransactionNoGasError = withStyles(styles)( - ({ classes, children, publicKey, openLink, closeAction }) => { + ({ classes, children, address, openLink, closeAction }) => { const gasExplanationUrl = 'https://help.selfkey.org/article/87-how-does-gas-impact-transaction-speed'; const handleLinkClick = event => { @@ -30,7 +30,7 @@ export const TransactionNoGasError = withStyles(styles)( openLink(gasExplanationUrl); }; return ( - +
You do not have enough Ethereum (ETH) to pay for the network transaction diff --git a/src/renderer/transaction/transaction-no-gas-error/containers/transaction-no-gas-error.js b/src/renderer/transaction/transaction-no-gas-error/containers/transaction-no-gas-error.js index 78433a88e..f4fccfdf0 100644 --- a/src/renderer/transaction/transaction-no-gas-error/containers/transaction-no-gas-error.js +++ b/src/renderer/transaction/transaction-no-gas-error/containers/transaction-no-gas-error.js @@ -32,7 +32,7 @@ class TransactionNoGasErrorContainer extends Component { const mapStateToProps = state => { return { - publicKey: getWallet(state).publicKey + address: getWallet(state).address }; }; diff --git a/src/renderer/transaction/transaction-no-key-error/components/transaction-no-key-error.jsx b/src/renderer/transaction/transaction-no-key-error/components/transaction-no-key-error.jsx index c46e04518..2fa9c2e46 100644 --- a/src/renderer/transaction/transaction-no-key-error/components/transaction-no-key-error.jsx +++ b/src/renderer/transaction/transaction-no-key-error/components/transaction-no-key-error.jsx @@ -19,9 +19,9 @@ const styles = theme => ({ }); export const TransactionNoKeyError = withStyles(styles)( - ({ classes, children, publicKey, closeAction }) => { + ({ classes, children, address, closeAction }) => { return ( - +
You do not have enough KEY tokens to pay for this Marketplace Application. diff --git a/src/renderer/transaction/transaction-no-key-error/containers/transaction-no-key-error.js b/src/renderer/transaction/transaction-no-key-error/containers/transaction-no-key-error.js index 887a251fa..ec4dffe3f 100644 --- a/src/renderer/transaction/transaction-no-key-error/containers/transaction-no-key-error.js +++ b/src/renderer/transaction/transaction-no-key-error/containers/transaction-no-key-error.js @@ -23,7 +23,7 @@ class TransactionNoKeyErrorContainer extends Component { const mapStateToProps = state => { return { - publicKey: getWallet(state).publicKey + address: getWallet(state).address }; }; diff --git a/src/renderer/transaction/transactions-history/index.jsx b/src/renderer/transaction/transactions-history/index.jsx index 86c0a52f3..d2883b4fd 100644 --- a/src/renderer/transaction/transactions-history/index.jsx +++ b/src/renderer/transaction/transactions-history/index.jsx @@ -238,8 +238,8 @@ class TransactionsHistory extends Component { }; hasSent = transaction => { - const publicKey = this.props.wallet.publicKey || ''; - return transaction.from.toLowerCase() === publicKey.toLowerCase(); + const address = this.props.wallet.address || ''; + return transaction.from.toLowerCase() === address.toLowerCase(); }; renderDate(timestamp) { diff --git a/src/renderer/wallet/create/backup-address.jsx b/src/renderer/wallet/create/backup-address.jsx index b4b8ae773..8d1542bb9 100644 --- a/src/renderer/wallet/create/backup-address.jsx +++ b/src/renderer/wallet/create/backup-address.jsx @@ -122,10 +122,10 @@ class BackupAddress extends Component { id="publicKey" fullWidth disableUnderline={true} - value={this.props.publicKey} + value={this.props.address} endAdornment={ - + } disabled @@ -165,7 +165,7 @@ class BackupAddress extends Component { const mapStateToProps = (state, props) => { return { - publicKey: walletSelectors.getWallet(state).publicKey, + address: walletSelectors.getWallet(state).address, fileDownloaded: createWalletSelectors.selectCreateWallet(state).fileDownloaded }; }; diff --git a/src/renderer/wallet/main/index.jsx b/src/renderer/wallet/main/index.jsx index c9b2dcc07..c4a09aebb 100644 --- a/src/renderer/wallet/main/index.jsx +++ b/src/renderer/wallet/main/index.jsx @@ -82,7 +82,7 @@ const contentWrapperStyle = { class Main extends Component { setMatomoId = () => { - ReactPiwik.push(['setUserId', md5(this.props.publicKey)]); + ReactPiwik.push(['setUserId', md5(this.props.address)]); ReactPiwik.push(['setCustomVariable', 1, 'machineId', window.machineId, 'visit']); ReactPiwik.push(['setCustomVariable', 2, 'walletType', this.props.walletType, 'visit']); ReactPiwik.push(['setCustomVariable', 3, 'walletVersion', window.appVersion, 'visit']); @@ -250,7 +250,7 @@ class Main extends Component { const mapStateToProps = (state, props) => { return { - publicKey: walletSelectors.getWallet(state).publicKey, + address: walletSelectors.getWallet(state).address, walletType: appSelectors.selectWalletType(state) }; }; diff --git a/src/renderer/wallet/unlock/existing-address.jsx b/src/renderer/wallet/unlock/existing-address.jsx index 1012c1cea..a72f48aff 100644 --- a/src/renderer/wallet/unlock/existing-address.jsx +++ b/src/renderer/wallet/unlock/existing-address.jsx @@ -121,8 +121,8 @@ class ExistingAddress extends Component { {wallets.map((wallet, index) => ( {wallet.name - ? `${wallet.name} - ${wallet.publicKey}` - : wallet.publicKey} + ? `${wallet.name} - ${wallet.address}` + : wallet.address} ))} diff --git a/test/e2e/address-book/common-steps.js b/test/e2e/address-book/common-steps.js index 99187d96f..083fe0d55 100644 --- a/test/e2e/address-book/common-steps.js +++ b/test/e2e/address-book/common-steps.js @@ -2,7 +2,7 @@ const tools = require('../../utils/tools.js'); const data = require('../../data/data.json'); const delay = require('delay'); -let publicKey; +let address; let privateKey; export const givenUserHasOpenedAddressBookScreen = given => { @@ -22,7 +22,7 @@ export const givenUserHasOpenedAddressBookScreen = given => { .then(() => delay(2000)) .then(() => tools.app.client.getValue('#publicKey')) .then(pubKey => { - publicKey = pubKey; + address = pubKey; return tools.regStep(tools.app, '#keystoreNext'); }) .then(() => tools.app.client.getValue('#privateKey')) @@ -88,5 +88,5 @@ export const whenUserClicksOnAddAddressButton = when => { }; export const getPublicKey = () => { - return publicKey; + return address; }; diff --git a/test/e2e/marketplace/bank-accounts/common-step.js b/test/e2e/marketplace/bank-accounts/common-step.js index 4343a3415..5f57ad3bd 100644 --- a/test/e2e/marketplace/bank-accounts/common-step.js +++ b/test/e2e/marketplace/bank-accounts/common-step.js @@ -2,7 +2,7 @@ const tools = require('../../../utils/tools.js'); const data = require('../../../data/data.json'); const delay = require('delay'); -let publicKey; +let address; let privateKey; export const givenUserHasOpenedTheMarketplaceScreen = given => { @@ -22,7 +22,7 @@ export const givenUserHasOpenedTheMarketplaceScreen = given => { .then(() => delay(2000)) .then(() => tools.app.client.getValue('#publicKey')) .then(pubKey => { - publicKey = pubKey; + address = pubKey; return tools.regStep(tools.app, '#keystoreNext'); }) .then(() => tools.app.client.getValue('#privateKey')) @@ -62,7 +62,7 @@ export const givenUserHasOpenedTheBankAccountsScreen = given => { .then(() => delay(2000)) .then(() => tools.app.client.getValue('#publicKey')) .then(pubKey => { - publicKey = pubKey; + address = pubKey; return tools.regStep(tools.app, '#keystoreNext'); }) .then(() => tools.app.client.getValue('#privateKey')) @@ -97,7 +97,7 @@ export const givenUserHasOpenedTheJurisdictionDetailedScreen = given => { .then(() => delay(2000)) .then(() => tools.app.client.getValue('#publicKey')) .then(pubKey => { - publicKey = pubKey; + address = pubKey; return tools.regStep(tools.app, '#keystoreNext'); }) .then(() => tools.app.client.getValue('#privateKey')) @@ -119,7 +119,7 @@ export const givenUserHasOpenedTheJurisdictionDetailedScreen = given => { }; export const getPublicKey = () => { - return publicKey; + return address; }; export const getPrivateKey = () => { From 6c7675061e541bf2e35f67660c2360e3454ee26c Mon Sep 17 00:00:00 2001 From: Maxim Kovalov Date: Thu, 26 Sep 2019 17:18:54 +0300 Subject: [PATCH 159/207] feat(wallet-setup): remove wallet setup --- src/main/wallet/wallet-service.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/main/wallet/wallet-service.js b/src/main/wallet/wallet-service.js index 5d6224b57..5e4341bff 100644 --- a/src/main/wallet/wallet-service.js +++ b/src/main/wallet/wallet-service.js @@ -196,13 +196,6 @@ export class WalletService { }); } - updateWalletSetup(setup, id) { - return Wallet.updateSetup({ - id, - setup: setup - }); - } - async updateDID(id, did) { did = did.replace('did:selfkey:', ''); return Wallet.updateDID({ From dbf5874085b860beae4f6cb953b714803ccf64da Mon Sep 17 00:00:00 2001 From: Andre Goncalves Date: Thu, 26 Sep 2019 15:40:16 +0100 Subject: [PATCH 160/207] fix: fix and refactor missing props in marketplace components --- .../checkout/checkout-container.jsx | 1 + .../checkout/payment-complete-container.jsx | 10 +++++++--- .../bank-accounts/checkout/payment-container.jsx | 13 ++++++++----- .../incorporations-checkout-container.jsx | 8 +++++--- ...incorporations-payment-complete-container.jsx | 5 ++--- .../incorporations-payment-container.jsx | 16 +++++++++------- .../details/incorporations-details-container.jsx | 5 +++-- 7 files changed, 35 insertions(+), 23 deletions(-) diff --git a/src/renderer/marketplace/bank-accounts/checkout/checkout-container.jsx b/src/renderer/marketplace/bank-accounts/checkout/checkout-container.jsx index 80def7514..3d3e27239 100644 --- a/src/renderer/marketplace/bank-accounts/checkout/checkout-container.jsx +++ b/src/renderer/marketplace/bank-accounts/checkout/checkout-container.jsx @@ -60,6 +60,7 @@ class BankAccountsCheckoutContainer extends MarketplaceBankAccountsComponent { const { jurisdiction, templateId, vendorId } = this.props; const { region } = jurisdiction.data; + // TODO: get URLs and vendor name from the RP store this.props.dispatch( kycOperations.startCurrentApplicationOperation( vendorId, diff --git a/src/renderer/marketplace/bank-accounts/checkout/payment-complete-container.jsx b/src/renderer/marketplace/bank-accounts/checkout/payment-complete-container.jsx index 6f955966d..d94783d32 100644 --- a/src/renderer/marketplace/bank-accounts/checkout/payment-complete-container.jsx +++ b/src/renderer/marketplace/bank-accounts/checkout/payment-complete-container.jsx @@ -17,7 +17,7 @@ class BankAccountsPaymentCompleteContainer extends MarketplaceBankAccountsCompon } async componentDidMount() { - const { transaction, jurisdiction } = this.props; + const { transaction, jurisdiction, vendorId } = this.props; this.saveTransactionHash(); this.clearRelyingParty(); @@ -27,7 +27,7 @@ class BankAccountsPaymentCompleteContainer extends MarketplaceBankAccountsCompon price: jurisdiction.price, code: jurisdiction.data.accountCode, jurisdiction: jurisdiction.data.region, - rpName: 'Bank Accounts' + rpName: vendorId }); } @@ -73,6 +73,7 @@ class BankAccountsPaymentCompleteContainer extends MarketplaceBankAccountsCompon onContinueClick = () => this.props.dispatch(push(this.getNextRoute())); render() { + // TODO: get vendor email from the RP return ( { - const { accountCode, vendorId } = props.match.params; + const { accountCode, vendorId, templateId } = props.match.params; const authenticated = true; return { + accountCode, + templateId, + vendorId, jurisdiction: marketplaceSelectors.selectBankJurisdictionByAccountCode(state, accountCode), transaction: transactionSelectors.getTransaction(state), publicKey: getWallet(state).publicKey, diff --git a/src/renderer/marketplace/bank-accounts/checkout/payment-container.jsx b/src/renderer/marketplace/bank-accounts/checkout/payment-container.jsx index 3ee4cac99..9e1dc44be 100644 --- a/src/renderer/marketplace/bank-accounts/checkout/payment-container.jsx +++ b/src/renderer/marketplace/bank-accounts/checkout/payment-container.jsx @@ -29,16 +29,18 @@ class BankAccountsPaymentContainer extends MarketplaceBankAccountsComponent { const price = this.priceInKEY(jurisdiction.price); const walletAddress = jurisdiction.walletAddress; const vendorDID = jurisdiction.didAddress; + // TODO: get vendor name from RP store + const vendorName = VENDOR_NAME; this.props.dispatch( ordersOperations.startOrderOperation({ + productInfo: `Bank account in ${jurisdiction.data.region}`, applicationId: application.id, amount: price, - vendorId: vendorId, + vendorId, itemId: accountCode, vendorDID, - productInfo: `Bank account in ${jurisdiction.data.region}`, - vendorName: VENDOR_NAME, + vendorName, backUrl: this.cancelRoute(), completeUrl: this.paymentCompleteRoute(), vendorWallet: featureIsEnabled('paymentContract') ? '' : walletAddress @@ -54,12 +56,13 @@ class BankAccountsPaymentContainer extends MarketplaceBankAccountsComponent { } const mapStateToProps = (state, props) => { - const { accountCode, vendorId } = props.match.params; + const { accountCode, templateId, vendorId } = props.match.params; const authenticated = true; return { - vendorId, accountCode, + templateId, + vendorId, jurisdiction: marketplaceSelectors.selectBankJurisdictionByAccountCode(state, accountCode), publicKey: getWallet(state).publicKey, keyRate: pricesSelectors.getRate(state, 'KEY', 'USD'), diff --git a/src/renderer/marketplace/incorporation/checkout/incorporations-checkout-container.jsx b/src/renderer/marketplace/incorporation/checkout/incorporations-checkout-container.jsx index e474666aa..2eacf6e6e 100644 --- a/src/renderer/marketplace/incorporation/checkout/incorporations-checkout-container.jsx +++ b/src/renderer/marketplace/incorporation/checkout/incorporations-checkout-container.jsx @@ -18,6 +18,7 @@ import { MarketplaceIncorporationsComponent } from '../common/marketplace-incorp const styles = theme => ({}); const CRYPTOCURRENCY = config.constants.primaryToken; const FIXED_GAS_LIMIT_PRICE = 21000; +const VENDOR_NAME = 'Far Horizon Capital Inc'; class IncorporationsCheckoutContainer extends MarketplaceIncorporationsComponent { async componentDidMount() { @@ -61,6 +62,7 @@ class IncorporationsCheckoutContainer extends MarketplaceIncorporationsComponent const { program, vendorId, templateId } = this.props; const { region } = program.data; + // TODO: get URLs and vendor name from the RP store this.props.dispatch( kycOperations.startCurrentApplicationOperation( vendorId, @@ -73,7 +75,7 @@ class IncorporationsCheckoutContainer extends MarketplaceIncorporationsComponent will result in delays in the incorporation process. You may also be asked to provide more information by the service provider`, 'conducting KYC', - 'Far Horizon Capital Inc', + VENDOR_NAME, 'https://flagtheory.com/privacy-policy', 'http://flagtheory.com/terms-and-conditions' ) @@ -110,12 +112,12 @@ class IncorporationsCheckoutContainer extends MarketplaceIncorporationsComponent } const mapStateToProps = (state, props) => { - const { companyCode, vendorId, countryCode, templateId } = props.match.params; + const { companyCode, countryCode, templateId, vendorId } = props.match.params; const authenticated = true; return { - vendorId, countryCode, templateId, + vendorId, program: marketplaceSelectors.selectIncorporationByFilter( state, c => c.data.companyCode === companyCode diff --git a/src/renderer/marketplace/incorporation/checkout/incorporations-payment-complete-container.jsx b/src/renderer/marketplace/incorporation/checkout/incorporations-payment-complete-container.jsx index 7e60890ca..7f94dfb61 100644 --- a/src/renderer/marketplace/incorporation/checkout/incorporations-payment-complete-container.jsx +++ b/src/renderer/marketplace/incorporation/checkout/incorporations-payment-complete-container.jsx @@ -66,15 +66,14 @@ class IncorporationsPaymentCompleteContainer extends MarketplaceIncorporationsCo } }; - getNextRoute = () => { - return this.selfKeyIdRoute(); - }; + getNextRoute = () => this.selfKeyIdRoute(); onBackClick = () => this.props.dispatch(push(this.cancelRoute())); onContinueClick = () => this.props.dispatch(push(this.getNextRoute())); render() { + // TODO: get vendor email from the RP const body = ( diff --git a/src/renderer/marketplace/incorporation/checkout/incorporations-payment-container.jsx b/src/renderer/marketplace/incorporation/checkout/incorporations-payment-container.jsx index 2768cea50..abf1bd784 100644 --- a/src/renderer/marketplace/incorporation/checkout/incorporations-payment-container.jsx +++ b/src/renderer/marketplace/incorporation/checkout/incorporations-payment-container.jsx @@ -11,7 +11,6 @@ import { ordersOperations } from 'common/marketplace/orders'; import { MarketplaceIncorporationsComponent } from '../common/marketplace-incorporations-component'; const styles = theme => ({}); -// TODO: future improvement load from rp config const VENDOR_NAME = 'Far Horizon Capital Inc'; class IncorporationsPaymentContainer extends MarketplaceIncorporationsComponent { @@ -29,16 +28,19 @@ class IncorporationsPaymentContainer extends MarketplaceIncorporationsComponent const application = this.getLastApplication(); const price = this.priceInKEY(program.price); const walletAddress = program.walletAddress; + const vendorDID = program.didAddress; + // TODO: get vendor name from RP store + const vendorName = VENDOR_NAME; this.props.dispatch( ordersOperations.startOrderOperation({ + productInfo: `Incorporate in ${program.Region}`, applicationId: application.id, amount: price, - vendorId: vendorId, + vendorId, itemId: companyCode, - vendorDID: program.didAddress, - productInfo: `Incorporate in ${program.Region}`, - vendorName: VENDOR_NAME, + vendorDID, + vendorName, backUrl: this.cancelRoute(), completeUrl: this.paymentCompleteRoute(), vendorWallet: featureIsEnabled('paymentContract') ? '' : walletAddress @@ -54,12 +56,12 @@ class IncorporationsPaymentContainer extends MarketplaceIncorporationsComponent } const mapStateToProps = (state, props) => { - const { companyCode, vendorId, templateId } = props.match.params; + const { companyCode, templateId, vendorId } = props.match.params; const authenticated = true; return { companyCode, - vendorId, templateId, + vendorId, program: marketplaceSelectors.selectIncorporationByFilter( state, c => c.data.companyCode === companyCode diff --git a/src/renderer/marketplace/incorporation/details/incorporations-details-container.jsx b/src/renderer/marketplace/incorporation/details/incorporations-details-container.jsx index 3b8ed75e7..769226d4f 100644 --- a/src/renderer/marketplace/incorporation/details/incorporations-details-container.jsx +++ b/src/renderer/marketplace/incorporation/details/incorporations-details-container.jsx @@ -189,9 +189,10 @@ const mapStateToProps = (state, props) => { cryptoCurrency: config.constants.primaryToken }; return { - vendorId, - templateId, + companyCode, countryCode, + templateId, + vendorId, program: marketplaceSelectors.selectIncorporationByFilter( state, c => c.data.companyCode === companyCode From 06f9c08062c9f19493375cb6412186141fbe3e97 Mon Sep 17 00:00:00 2001 From: Andre Goncalves Date: Thu, 26 Sep 2019 18:39:45 +0100 Subject: [PATCH 161/207] fix: missing corp feature flag prop --- src/renderer/wallet/main/toolbar.jsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/renderer/wallet/main/toolbar.jsx b/src/renderer/wallet/main/toolbar.jsx index d129f5800..9085b62ff 100644 --- a/src/renderer/wallet/main/toolbar.jsx +++ b/src/renderer/wallet/main/toolbar.jsx @@ -330,7 +330,8 @@ class Toolbar extends Component { profiles, wallet, onCreateCorporateProfileClick, - primaryToken + primaryToken, + showCorporate } = this.props; return (
@@ -391,6 +392,7 @@ class Toolbar extends Component { onClickCorporate={onCreateCorporateProfileClick} onProfileSelect={onProfileSelect} closeProfile={closeProfile} + showCorporate={showCorporate} />
From 6e5eb53fb88cdddd0e8b0ac9a55f914607b3a446 Mon Sep 17 00:00:00 2001 From: Maxim Kovalov Date: Fri, 27 Sep 2019 11:09:19 +0300 Subject: [PATCH 162/207] fix: create wallet --- src/common/create-wallet/index.js | 4 +++- src/renderer/wallet/create/backup-address.jsx | 14 +++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/common/create-wallet/index.js b/src/common/create-wallet/index.js index 68c7240ee..3dee94c2a 100644 --- a/src/common/create-wallet/index.js +++ b/src/common/create-wallet/index.js @@ -1,6 +1,7 @@ import { getGlobalContext } from 'common/context'; import { createAliasedAction } from 'electron-redux'; import { walletOperations, walletSelectors } from '../wallet'; +import { appOperations } from '../app'; export const initialState = { password: '', @@ -27,8 +28,9 @@ const createWalletActions = { const createWallet = () => async (dispatch, getState) => { const walletService = getGlobalContext().walletService; - const wallet = await walletService.createWallet(getState().createWallet.password); + const wallet = await walletService.createWalletWithPassword(getState().createWallet.password); await dispatch(walletOperations.updateWalletWithBalance(wallet)); + await dispatch(appOperations.unlockWalletOperation(wallet, 'privateKey')); }; const downloadFile = toPath => async (dispatch, getState) => { diff --git a/src/renderer/wallet/create/backup-address.jsx b/src/renderer/wallet/create/backup-address.jsx index 8d1542bb9..f12c5bc41 100644 --- a/src/renderer/wallet/create/backup-address.jsx +++ b/src/renderer/wallet/create/backup-address.jsx @@ -107,16 +107,16 @@ class BackupAddress extends Component { - Your public key is a unique address on the Ethereum - blockchain. Think of it like a bank account number that you - own, used to send and receive Ether or tokens. The ability - to authorize transactions on this address is encrypted by - the password you just created. Download a backup and save - this address in a convenient location. + Your address in Etherium network. Think of it like a bank + account number that you own, used to send and receive Ether + or tokens. The ability to authorize transactions on this + address is encrypted by the password you just created. + Download a backup and save this address in a convenient + location.
- Your Public Key + Your Address Date: Fri, 27 Sep 2019 11:42:39 +0300 Subject: [PATCH 163/207] fix: typo --- src/renderer/wallet/create/backup-address.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/wallet/create/backup-address.jsx b/src/renderer/wallet/create/backup-address.jsx index f12c5bc41..bd856509a 100644 --- a/src/renderer/wallet/create/backup-address.jsx +++ b/src/renderer/wallet/create/backup-address.jsx @@ -107,7 +107,7 @@ class BackupAddress extends Component {
- Your address in Etherium network. Think of it like a bank + Your address in Ethereum network. Think of it like a bank account number that you own, used to send and receive Ether or tokens. The ability to authorize transactions on this address is encrypted by the password you just created. From 3127aeae54c1a61016fe8cd0e8b655095947346b Mon Sep 17 00:00:00 2001 From: Maxim Kovalov Date: Fri, 27 Sep 2019 14:10:24 +0300 Subject: [PATCH 164/207] feat(pdf-viewer): fix for big files and blob --- src/main/preload.js | 1 + src/renderer/selfkey-id/main/components/create-attribute.jsx | 2 +- src/renderer/selfkey-id/main/components/edit-attribute.jsx | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/preload.js b/src/main/preload.js index 2d8eec84a..a96eab42e 100644 --- a/src/main/preload.js +++ b/src/main/preload.js @@ -82,6 +82,7 @@ window.openFileSelectDialog = event => { }; window.openPDF = href => { + if (!href) return; const { BrowserWindow } = electron.remote; const win = new BrowserWindow({ width: 800, height: 600 }); PDFWindow.addSupport(win); diff --git a/src/renderer/selfkey-id/main/components/create-attribute.jsx b/src/renderer/selfkey-id/main/components/create-attribute.jsx index 8c764a4f4..4da7dccf5 100644 --- a/src/renderer/selfkey-id/main/components/create-attribute.jsx +++ b/src/renderer/selfkey-id/main/components/create-attribute.jsx @@ -216,7 +216,7 @@ class CreateAttributeComponent extends Component { onSubmit={this.handleSave} onError={this.handleErrors} transformErrors={transformErrors} - onPDFOpen={file => window.openPDF(file.content)} + onPDFOpen={file => window.openPDF(file.content || file.url)} > {this.state.documentError && ( diff --git a/src/renderer/selfkey-id/main/components/edit-attribute.jsx b/src/renderer/selfkey-id/main/components/edit-attribute.jsx index d5b02141b..d764baa64 100644 --- a/src/renderer/selfkey-id/main/components/edit-attribute.jsx +++ b/src/renderer/selfkey-id/main/components/edit-attribute.jsx @@ -174,7 +174,7 @@ class EditAttributeComponent extends Component { onSubmit={this.handleSave} onError={this.handleErrors} transformErrors={transformErrors} - onPDFOpen={file => window.openPDF(file.content)} + onPDFOpen={file => window.openPDF(file.content || file.url)} > {this.state.documentError && ( From 5d2a29c04bc219f681ca3be396625f694bcdc160 Mon Sep 17 00:00:00 2001 From: Maxim Kovalov Date: Fri, 27 Sep 2019 14:53:52 +0300 Subject: [PATCH 165/207] fix(pdf): fix blob links --- package.json | 2 +- yarn.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 3cbcea213..caa23a03c 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,7 @@ "electron-devtools-installer": "2.2.4", "electron-dl": "1.14.0", "electron-is": "3.0.0", - "electron-pdf-window": "https://github.com/SelfKeyFoundation/electron-pdf-window.git#15ef0b0", + "electron-pdf-window": "https://github.com/SelfKeyFoundation/electron-pdf-window.git#289c1aeb35e9e1da30ab8eabe52428dc87cc1220", "electron-redux": "1.3.1", "ethereumjs-tx": "1.3.7", "ethereumjs-util": "6.1.0", diff --git a/yarn.lock b/yarn.lock index 77f312af5..e86ceabce 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8237,9 +8237,9 @@ electron-osx-sign@0.4.11: minimist "^1.2.0" plist "^3.0.1" -"electron-pdf-window@https://github.com/SelfKeyFoundation/electron-pdf-window.git#15ef0b0": +"electron-pdf-window@https://github.com/SelfKeyFoundation/electron-pdf-window.git#289c1aeb35e9e1da30ab8eabe52428dc87cc1220": version "1.0.13" - resolved "https://github.com/SelfKeyFoundation/electron-pdf-window.git#15ef0b0e718cd98d69df53c3bdacab9c7f5cc847" + resolved "https://github.com/SelfKeyFoundation/electron-pdf-window.git#289c1aeb35e9e1da30ab8eabe52428dc87cc1220" dependencies: deep-extend "^0.6.0" file-type "^10.9.0" From 9af0143fd8eb58c3d8bad3c80a7831fb007b3475 Mon Sep 17 00:00:00 2001 From: Maxim Kovalov Date: Fri, 27 Sep 2019 15:10:58 +0300 Subject: [PATCH 166/207] feat(dev-attr-types): add env var to controll source --- src/common/config.js | 9 +++++++-- src/main/identity/document.js | 4 ++-- src/main/identity/id-attribute-type.js | 4 ++-- src/main/identity/id-attribute.js | 5 ++--- src/main/identity/repository.js | 5 ++--- src/main/identity/ui-schema.js | 5 ++--- 6 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/common/config.js b/src/common/config.js index 79f35e998..a9ffa5ca9 100644 --- a/src/common/config.js +++ b/src/common/config.js @@ -35,6 +35,9 @@ const ALL_COUNTRIES_INFO_URL = process.env.ALL_COUNTRIES_INFO_URL; const MATOMO_SITE = process.env.MATOMO_SITE; const DEPOSIT_PRICE_OVERRIDE = process.env.DEPOSIT_PRICE_OVERRIDE; +// development or production +const ATTRIBUTE_TYPE_SOURCE_OVERRIDE = process.env.ATTRIBUTE_TYPE_SOURCE_OVERRIDE; + let userDataDirectoryPath = ''; let walletsDirectoryPath = ''; if (electron.app) { @@ -140,7 +143,8 @@ const dev = { corporate: true }, testWalletAddress: '0x23d233933c86f93b74705cf0d236b39f474249f8', - testDidAddress: '0xee10a3335f48e10b444e299cf017d57879109c1e32cec3e31103ceca7718d0ec' + testDidAddress: '0xee10a3335f48e10b444e299cf017d57879109c1e32cec3e31103ceca7718d0ec', + attributeTypeSource: ATTRIBUTE_TYPE_SOURCE_OVERRIDE || 'development' }; const prod = { @@ -161,7 +165,8 @@ const prod = { paymentContract: false, scheduler: true, corporate: false - } + }, + attributeTypeSource: ATTRIBUTE_TYPE_SOURCE_OVERRIDE || 'production' }; const setupFilesPath = getSetupFilePath(); diff --git a/src/main/identity/document.js b/src/main/identity/document.js index ce7b939f0..942ffd45c 100644 --- a/src/main/identity/document.js +++ b/src/main/identity/document.js @@ -1,9 +1,9 @@ import { Model } from 'objection'; import BaseModel from '../common/base-model'; -import { isDevMode } from 'common/utils/common'; +import config from 'common/config'; import { formatDataUrl } from 'common/utils/document'; const TABLE_NAME = 'documents'; -const env = isDevMode() ? 'development' : 'production'; +const env = config.attributeTypeSource; export class Document extends BaseModel { static tableName = TABLE_NAME; static idColumn = 'id'; diff --git a/src/main/identity/id-attribute-type.js b/src/main/identity/id-attribute-type.js index 7c9b9b3a8..93107724b 100644 --- a/src/main/identity/id-attribute-type.js +++ b/src/main/identity/id-attribute-type.js @@ -1,9 +1,9 @@ import { Model, transaction } from 'objection'; import BaseModel from '../common/base-model'; -import { isDevMode } from 'common/utils/common'; +import config from 'common/config'; import { jsonSchema } from 'common/identity/utils'; import { Logger } from 'common/logger'; -const env = isDevMode() ? 'development' : 'production'; +const env = config.attributeTypeSource; const log = new Logger('id-attribute-type-model'); const TABLE_NAME = 'id_attribute_types'; diff --git a/src/main/identity/id-attribute.js b/src/main/identity/id-attribute.js index 486c0808b..0b177171d 100644 --- a/src/main/identity/id-attribute.js +++ b/src/main/identity/id-attribute.js @@ -2,9 +2,8 @@ import { Model, transaction } from 'objection'; import _ from 'lodash'; import BaseModel from '../common/base-model'; import Document from './document'; -import { isDevMode } from 'common/utils/common'; - -const env = isDevMode() ? 'development' : 'production'; +import config from 'common/config'; +const env = config.attributeTypeSource; const TABLE_NAME = 'id_attributes'; export class IdAttribute extends BaseModel { diff --git a/src/main/identity/repository.js b/src/main/identity/repository.js index c8a62910d..c0f2d9b80 100644 --- a/src/main/identity/repository.js +++ b/src/main/identity/repository.js @@ -1,12 +1,11 @@ import { Model, transaction } from 'objection'; import BaseModel from '../common/base-model'; import { jsonSchema } from 'common/identity/utils'; -import { isDevMode } from 'common/utils/common'; import IdAttributeType from './id-attribute-type'; import { Logger } from 'common/logger'; import { UiSchema } from './ui-schema'; - -const env = isDevMode() ? 'development' : 'production'; +import config from 'common/config'; +const env = config.attributeTypeSource; const log = new Logger('repository-model'); const TABLE_NAME = 'repository'; diff --git a/src/main/identity/ui-schema.js b/src/main/identity/ui-schema.js index dde80bf6b..9a13af13b 100644 --- a/src/main/identity/ui-schema.js +++ b/src/main/identity/ui-schema.js @@ -1,10 +1,9 @@ import { Model, transaction } from 'objection'; import BaseModel from '../common/base-model'; +import config from 'common/config'; import { jsonSchema } from 'common/identity/utils'; -import { isDevMode } from 'common/utils/common'; import { Logger } from 'common/logger'; - -const env = isDevMode() ? 'development' : 'production'; +const env = config.attributeTypeSource; const log = new Logger('ui-schema-model'); const UI_SCHEMA_EXPIRES = 86400000; // 1 day From fe7b8a2bb26e0613e1a84adfa3a65376db190a34 Mon Sep 17 00:00:00 2001 From: Andre Goncalves Date: Fri, 27 Sep 2019 15:10:30 +0100 Subject: [PATCH 167/207] feat: wire-up --- src/common/identity/operations.js | 1 + src/common/identity/selectors.js | 9 +- .../common/corporate-applications.jsx | 11 +- .../corporate/common/corporate-cap-table.jsx | 4 +- .../corporate/common/corporate-component.jsx | 5 + .../corporate/common/corporate-details.jsx | 16 +- .../corporate/common/corporate-org-chart.jsx | 14 +- .../common/corporate-shareholding.jsx | 13 +- .../dashboard/dashboard-container.jsx | 141 ++++++++++++++++++ .../corporate/dashboard/dashboard-page.jsx | 41 ----- .../corporate/dashboard/overview-tab.jsx | 66 +++++++- src/renderer/corporate/index.js | 4 +- src/renderer/wallet/main/index.jsx | 4 +- 13 files changed, 253 insertions(+), 76 deletions(-) create mode 100644 src/renderer/corporate/common/corporate-component.jsx create mode 100644 src/renderer/corporate/dashboard/dashboard-container.jsx delete mode 100644 src/renderer/corporate/dashboard/dashboard-page.jsx diff --git a/src/common/identity/operations.js b/src/common/identity/operations.js index 3dc4435cb..54768426c 100644 --- a/src/common/identity/operations.js +++ b/src/common/identity/operations.js @@ -151,6 +151,7 @@ const createCorporateProfileOperation = data => async (dispatch, getState) => { identityOperations.createIdentityOperation(wallet.id, 'corporate') ); } + await dispatch(identityOperations.setCurrentIdentityAction(identity.id)); const getTypeId = url => { return idAttributeTypes.find(idAttributeType => idAttributeType.url === url).id; }; diff --git a/src/common/identity/selectors.js b/src/common/identity/selectors.js index 250d27125..a8f2a6c23 100644 --- a/src/common/identity/selectors.js +++ b/src/common/identity/selectors.js @@ -234,6 +234,12 @@ const selectCorporateLegalEntityTypes = state => { return idType.content.enum; }; +const selectCurrentCorporateProfile = state => { + console.log(state); + const identity = identitySelectors.selectCurrentIdentity(state); + return identitySelectors.selectCorporateProfile(state, identity.id); +}; + const selectCorporateProfile = (state, id) => { const identity = identitySelectors.selectIdentityById(state, id); if (!identity) return {}; @@ -303,7 +309,8 @@ export const identitySelectors = { selectAllIdentities, selectCorporateJurisdictions, selectCorporateLegalEntityTypes, - selectCorporateProfile + selectCorporateProfile, + selectCurrentCorporateProfile }; export default identitySelectors; diff --git a/src/renderer/corporate/common/corporate-applications.jsx b/src/renderer/corporate/common/corporate-applications.jsx index 9212eedbe..42cd7335a 100644 --- a/src/renderer/corporate/common/corporate-applications.jsx +++ b/src/renderer/corporate/common/corporate-applications.jsx @@ -9,12 +9,15 @@ import { TableHead, TableBody, TableRow, - TableCell + TableCell, + withStyles } from '@material-ui/core'; import { HourGlassSmallIcon, CheckMaIcon, DeniedIcon, SmallTableHeadRow } from 'selfkey-ui'; -import { withStyles } from '@material-ui/core'; const styles = theme => ({ + container: { + width: '100%' + }, hr: { backgroundColor: '#303C49', border: 'none', @@ -42,7 +45,7 @@ const renderStatus = status => {
); } - if (status == 'rejected') { + if (status === 'rejected') { return ( Denied @@ -60,7 +63,7 @@ const renderStatus = status => { const CorporateApplicationsSummary = withStyles(styles)(props => { const { classes, applications = [] } = props; return ( - + diff --git a/src/renderer/corporate/common/corporate-cap-table.jsx b/src/renderer/corporate/common/corporate-cap-table.jsx index 18b16c9dd..8b88a2c7a 100644 --- a/src/renderer/corporate/common/corporate-cap-table.jsx +++ b/src/renderer/corporate/common/corporate-cap-table.jsx @@ -9,10 +9,10 @@ import { TableHead, TableBody, TableRow, - TableCell + TableCell, + withStyles } from '@material-ui/core'; import { EditTransparentIcon, SmallTableHeadRow } from 'selfkey-ui'; -import { withStyles } from '@material-ui/core'; const styles = theme => ({ hr: { diff --git a/src/renderer/corporate/common/corporate-component.jsx b/src/renderer/corporate/common/corporate-component.jsx new file mode 100644 index 000000000..bf86e089a --- /dev/null +++ b/src/renderer/corporate/common/corporate-component.jsx @@ -0,0 +1,5 @@ +import { Component } from 'react'; + +export default class CorporateComponent extends Component {} + +export { CorporateComponent }; diff --git a/src/renderer/corporate/common/corporate-details.jsx b/src/renderer/corporate/common/corporate-details.jsx index d5b7424cf..d8f0a2b46 100644 --- a/src/renderer/corporate/common/corporate-details.jsx +++ b/src/renderer/corporate/common/corporate-details.jsx @@ -1,7 +1,6 @@ import React from 'react'; -import { Grid, CardHeader, Card, CardContent, Typography } from '@material-ui/core'; +import { Grid, CardHeader, Card, CardContent, Typography, withStyles } from '@material-ui/core'; import { CheckMaIcon, AttributeAlertIcon, EditTransparentIcon } from 'selfkey-ui'; -import { withStyles } from '@material-ui/core'; const styles = theme => ({ hr: { @@ -58,13 +57,14 @@ const editAction = onEdit => ( ); const CorporateDetails = withStyles(styles)(props => { - const { classes, name, jurisdiction, type, date, address, onEdit } = props; + const { classes, profile, onEdit } = props; + console.log(profile); return ( @@ -81,25 +81,25 @@ const CorporateDetails = withStyles(styles)(props => { Jurisdiction - {renderAttr(jurisdiction)} + {renderAttr(profile.jurisdiction)}
Entity Type - {renderAttr(type)} + {renderAttr(profile.entityType)}
Incorporation Date - {renderAttr(date)} + {renderAttr(profile.creationDate)}
Address - {renderAttr(address)} + {renderAttr(profile.address)}
diff --git a/src/renderer/corporate/common/corporate-org-chart.jsx b/src/renderer/corporate/common/corporate-org-chart.jsx index b763f4b3c..8097f8120 100644 --- a/src/renderer/corporate/common/corporate-org-chart.jsx +++ b/src/renderer/corporate/common/corporate-org-chart.jsx @@ -1,7 +1,6 @@ import React from 'react'; -import { Grid, CardHeader, Card, CardContent } from '@material-ui/core'; +import { Grid, CardHeader, Card, CardContent, withStyles } from '@material-ui/core'; import { base, grey, EditTransparentIcon } from 'selfkey-ui'; -import { withStyles } from '@material-ui/core'; import 'react-orgchart/index.css'; import OrgChart from 'react-orgchart'; @@ -24,15 +23,16 @@ const styles = theme => ({ } }, orgChart: { - overflow: 'auto', + overflow: 'scroll', margin: 'auto', '& .initechNode': { border: `solid 1px ${grey}`, borderRadius: '3px', padding: '1em', - width: '150px', display: 'inline-block', - margin: '0 2px' + margin: '0 2px', + minWidth: '60px', + fontSize: '12px' }, '& .initechNode span': { display: 'block', @@ -71,7 +71,7 @@ const treeNode = ({ node }) => ( ); const CorporateOrgChart = withStyles(styles)(props => { - const { classes, name, cap = [], onEdit } = props; + const { classes, profile, cap = [], onEdit } = props; return ( @@ -84,7 +84,7 @@ const CorporateOrgChart = withStyles(styles)(props => {
diff --git a/src/renderer/corporate/common/corporate-shareholding.jsx b/src/renderer/corporate/common/corporate-shareholding.jsx index 1615228ca..b856196cb 100644 --- a/src/renderer/corporate/common/corporate-shareholding.jsx +++ b/src/renderer/corporate/common/corporate-shareholding.jsx @@ -1,7 +1,6 @@ import React from 'react'; -import { Grid, CardHeader, Card, CardContent, Typography } from '@material-ui/core'; +import { Grid, CardHeader, Card, CardContent, withStyles } from '@material-ui/core'; import { Chart } from 'react-google-charts'; -import { withStyles } from '@material-ui/core'; const styles = theme => ({ cardContainer: { @@ -91,7 +90,7 @@ const getChartData = cap => { const selectEvent = { eventName: 'select', callback: ({ chartWrapper }) => { - const selection = chartWrapper.getChart().getSelection(); + // const selection = chartWrapper.getChart().getSelection(); } }; @@ -104,7 +103,12 @@ const readyEvent = { } }; +/* let pieChartRef = null; +ref={c => { + pieChartRef = c; +}} +*/ const CorporateShareholding = withStyles(styles)(props => { const { classes, cap = [] } = props; @@ -126,9 +130,6 @@ const CorporateShareholding = withStyles(styles)(props => { height="300px" legend_toggle chartEvents={[selectEvent, readyEvent]} - ref={c => { - pieChartRef = c; - }} />
diff --git a/src/renderer/corporate/dashboard/dashboard-container.jsx b/src/renderer/corporate/dashboard/dashboard-container.jsx new file mode 100644 index 000000000..7f1e98d82 --- /dev/null +++ b/src/renderer/corporate/dashboard/dashboard-container.jsx @@ -0,0 +1,141 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import { identitySelectors } from 'common/identity'; +import { Typography, Grid, withStyles } from '@material-ui/core'; +import { CorporateComponent } from '../common/corporate-component'; +import { CorporateDashboardTabs } from './dashboard-tabs'; + +// TODO: replace with real data +const dummyMembers = [ + { + id: '1', + name: 'Giacomo Guilizzoni', + type: 'Person', + role: 'Director, Shareholder', + citizenship: 'Italy', + residency: 'Singapore', + shares: '45%' + }, + { + id: '2', + name: 'Marco Botton Ltd', + type: 'Corporate', + role: 'Shareholder', + citizenship: 'Hong Kong', + residency: 'Hong Kong', + shares: '9%' + }, + { + id: '3', + name: 'Big Things Ltd', + type: 'Corporate', + role: 'Shareholder', + citizenship: 'Hong Kong', + residency: 'Hong Kong', + shares: '41%' + }, + { + id: '4', + name: 'John Dafoe', + type: 'Person', + role: 'Director', + citizenship: 'France', + residency: 'France', + shares: '5%' + } +]; + +const dummyCorporateCapTable = [ + { + type: 'Person', + role: 'Director', + name: 'John Doe', + email: 'john.doe@email.com', + citizenship: 'Italy', + residency: 'Singapore', + shares: 0.5, + children: [] + }, + { + type: 'Corporate', + role: 'Shareholder', + name: 'ACME Inc', + email: null, + citizenship: 'Hong Kong', + residency: 'Hong Kong', + shares: 0.09, + children: dummyMembers + }, + { + type: 'Corporate', + role: 'Shareholder', + name: 'Apple Inc', + email: null, + citizenship: 'U.S.A.', + residency: 'U.S.A.', + shares: 0.41, + children: [] + } +]; + +const styles = theme => ({ + container: { + width: '100%' + }, + title: { + padding: '0' + }, + contentContainer: { + borderBottom: '1px solid #303C49' + } +}); +class CorporateDashboardContainer extends CorporateComponent { + state = { + tab: 'overview' + }; + + onTabChange = tab => this.setState({ tab }); + + render() { + const { classes } = this.props; + const { tab } = this.state; + console.log(this.props); + return ( + + + + SelfKey Corporate Vault + + + + + + + ); + } +} + +const mapStateToProps = (state, props) => { + return { + identity: identitySelectors.selectCurrentIdentity(state), + profile: identitySelectors.selectCurrentCorporateProfile(state), + applications: [], // marketplace applications, + members: dummyMembers, + cap: dummyCorporateCapTable + }; +}; + +const connectedComponent = connect(mapStateToProps)(CorporateDashboardContainer); +const styledComponent = withStyles(styles)(connectedComponent); +export { styledComponent as CorporateDashboardContainer }; diff --git a/src/renderer/corporate/dashboard/dashboard-page.jsx b/src/renderer/corporate/dashboard/dashboard-page.jsx deleted file mode 100644 index 14595bfd2..000000000 --- a/src/renderer/corporate/dashboard/dashboard-page.jsx +++ /dev/null @@ -1,41 +0,0 @@ -import React from 'react'; -import { Typography, Grid, withStyles } from '@material-ui/core'; -import { CorporateDashboardTabs } from './dashboard-tabs'; - -const styles = theme => ({ - container: { - width: '100%', - margin: '50px auto 0', - maxWidth: '960px' - }, - title: { - padding: '22px 0' - }, - contentContainer: { - borderBottom: '1px solid #303C49' - } -}); -export const CorporateDashboardPage = withStyles(styles)(props => { - const { classes, tab, onTabChange } = props; - return ( - - - - SelfKey Corporate Vault - - - - - - - ); -}); - -export default CorporateDashboardPage; diff --git a/src/renderer/corporate/dashboard/overview-tab.jsx b/src/renderer/corporate/dashboard/overview-tab.jsx index 07d6cdeb6..c91d613f9 100644 --- a/src/renderer/corporate/dashboard/overview-tab.jsx +++ b/src/renderer/corporate/dashboard/overview-tab.jsx @@ -1,9 +1,69 @@ import React from 'react'; -import { withStyles } from '@material-ui/core'; +import { Grid, withStyles } from '@material-ui/core'; +import { CorporateDetails } from '../common/corporate-details'; +import { CorporateApplicationsSummary } from '../common/corporate-applications'; +import { CorporateCapTable } from '../common/corporate-cap-table'; +import { CorporateShareholding } from '../common/corporate-shareholding'; +import { CorporateOrgChart } from '../common/corporate-org-chart'; -const styles = theme => ({}); +const styles = theme => ({ + flexGrow: { + flexGrow: 1, + width: '100%', + maxWidth: '100%', + overflow: 'hidden' + }, + CorporateShareholding: { + width: '550px' + } +}); -const CorporateOverviewTab = withStyles(styles)(({ classes }) =>
); +const CorporateOverviewTab = withStyles(styles)(({ classes, applications, profile, cap }) => ( +
+ + + + + + + + + + + + + + + + + + + + + +
+)); export { CorporateOverviewTab }; export default CorporateOverviewTab; diff --git a/src/renderer/corporate/index.js b/src/renderer/corporate/index.js index 71b5f872e..cb0fc9572 100644 --- a/src/renderer/corporate/index.js +++ b/src/renderer/corporate/index.js @@ -1,3 +1,3 @@ -import { CorporateDashboardPage } from './dashboard/dashboard-page'; +import { CorporateDashboardContainer } from './dashboard/dashboard-container'; -export { CorporateDashboardPage }; +export { CorporateDashboardContainer }; diff --git a/src/renderer/wallet/main/index.jsx b/src/renderer/wallet/main/index.jsx index c4a09aebb..fcd33a03a 100644 --- a/src/renderer/wallet/main/index.jsx +++ b/src/renderer/wallet/main/index.jsx @@ -54,7 +54,7 @@ import ReactPiwik from 'react-piwik'; import HardwareWalletTransactionTimer from '../../transaction/send/timer'; import CorporateWizardContainer from '../../corporate/wizard/corporate-wizard-container'; import CorporateAddMemberContainer from '../../corporate/member/corporate-add-member-container'; -import { CorporateDashboardPage } from '../../corporate'; +import { CorporateDashboardContainer } from '../../corporate'; const styles = theme => ({ headerSection: { @@ -240,7 +240,7 @@ class Main extends Component { /> From 63fbd17f28237e40a1cf525691b0bafa8608a9b6 Mon Sep 17 00:00:00 2001 From: Maxim Kovalov Date: Fri, 27 Sep 2019 17:15:22 +0300 Subject: [PATCH 168/207] feat(attribute): refactor attribute popups --- .babelrc | 4 +- .eslintrc.json | 6 +- .storybook/.babelrc | 23 +++++ .storybook/webpack.config.js | 24 +++++- package.json | 4 +- src/common/config.js | 12 +-- src/common/logger/config.js | 2 +- src/common/logger/index.js | 11 ++- .../attributes/create-attribute-container.js | 57 +++++++++++++ .../create-attribute.jsx | 18 +++- .../delete-attribute-container.js} | 23 +++-- .../delete-attribute.jsx | 0 .../edit-attribute-container.js} | 25 +++--- .../edit-attribute.jsx | 10 +-- src/renderer/attributes/index.js | 3 + .../transform-errors.js | 0 .../current-application-container.jsx | 7 +- .../main/containers/create-attribute-popup.js | 83 ------------------- .../main/containers/selfkey-id-overview.js | 15 ++-- stories/attribute.stories.js | 56 +++++++++++++ yarn.lock | 20 +++-- 21 files changed, 257 insertions(+), 146 deletions(-) create mode 100644 .storybook/.babelrc create mode 100644 src/renderer/attributes/create-attribute-container.js rename src/renderer/{selfkey-id/main/components => attributes}/create-attribute.jsx (94%) rename src/renderer/{selfkey-id/main/containers/delete-attribute-popup.js => attributes/delete-attribute-container.js} (50%) rename src/renderer/{selfkey-id/main/components => attributes}/delete-attribute.jsx (100%) rename src/renderer/{selfkey-id/main/containers/edit-attribute-popup.js => attributes/edit-attribute-container.js} (59%) rename src/renderer/{selfkey-id/main/components => attributes}/edit-attribute.jsx (95%) create mode 100644 src/renderer/attributes/index.js rename src/renderer/{selfkey-id/main/components => attributes}/transform-errors.js (100%) delete mode 100644 src/renderer/selfkey-id/main/containers/create-attribute-popup.js create mode 100644 stories/attribute.stories.js diff --git a/.babelrc b/.babelrc index 751963d6b..4a5561869 100644 --- a/.babelrc +++ b/.babelrc @@ -10,7 +10,5 @@ ], "@babel/preset-react" ], - "plugins": [ - "@babel/plugin-proposal-class-properties" - ] + "plugins": ["@babel/plugin-proposal-class-properties", "@babel/plugin-syntax-dynamic-import"] } diff --git a/.eslintrc.json b/.eslintrc.json index 83c13d9bb..0d4bc4d00 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -5,7 +5,8 @@ "sourceType": "module", "ecmaFeatures": { "jsx": true - } + }, + "allowImportExportEverywhere": true }, "parser": "babel-eslint", "env": { @@ -24,7 +25,8 @@ } ], "react/prop-types": 0, - "import/no-named-as-default": 0 + "import/no-named-as-default": 0, + "import/first": 0 }, "settings": { "react": { diff --git a/.storybook/.babelrc b/.storybook/.babelrc new file mode 100644 index 000000000..6effc9417 --- /dev/null +++ b/.storybook/.babelrc @@ -0,0 +1,23 @@ +{ + "presets": [ + [ + "@babel/preset-env", + { + "targets": { + "node": "current" + } + } + ], + "@babel/preset-react" + ], + "plugins": [ + "@babel/plugin-proposal-class-properties", + [ + "@babel/plugin-transform-runtime", + { + "regenerator": true + } + ], + "@babel/plugin-syntax-dynamic-import" + ] +} diff --git a/.storybook/webpack.config.js b/.storybook/webpack.config.js index 9408023b0..ed23dbc0d 100644 --- a/.storybook/webpack.config.js +++ b/.storybook/webpack.config.js @@ -1,4 +1,5 @@ const path = require('path'); +const webpack = require('webpack'); module.exports = async ({ config }) => { config.module.rules.push({ @@ -9,15 +10,36 @@ module.exports = async ({ config }) => { path.resolve(__dirname, '../node_modules/selfkey-ui/') ], options: { - presets: ['@babel/react'] + presets: [ + [ + '@babel/preset-env', + { + targets: { + node: 'current' + } + } + ], + '@babel/preset-react' + ], + plugins: [ + '@babel/plugin-proposal-class-properties', + '@babel/plugin-syntax-dynamic-import' + ] } }); + config.plugins.push( + new webpack.EnvironmentPlugin({ + STORYBOOK: '1' + }) + ); + config.resolve.modules = [ path.resolve(__dirname, '..', 'src'), path.resolve(__dirname, '..', 'node_modules') ]; config.resolve.extensions = ['.js', '.jsx', '.css', '.svg']; + config.node = { fs: 'empty' }; return config; }; diff --git a/package.json b/package.json index 3cbcea213..de0f3cf48 100644 --- a/package.json +++ b/package.json @@ -136,7 +136,8 @@ "devDependencies": { "@babel/core": "7.1.6", "@babel/plugin-proposal-class-properties": "7.1.0", - "@babel/plugin-syntax-dynamic-import": "7.2.0", + "@babel/plugin-syntax-dynamic-import": "^7.2.0", + "@babel/plugin-transform-runtime": "^7.6.2", "@babel/preset-env": "7.1.6", "@babel/preset-react": "7.0.0", "@commitlint/cli": "7.2.1", @@ -148,6 +149,7 @@ "@storybook/addon-links": "5.0.11", "@storybook/addons": "5.0.11", "@storybook/react": "5.0.11", + "acorn": "6.1.1", "babel-core": "7.0.0-bridge.0", "babel-eslint": "10.0.1", "babel-jest": "24.5.0", diff --git a/src/common/config.js b/src/common/config.js index 79f35e998..9b9b1ab35 100644 --- a/src/common/config.js +++ b/src/common/config.js @@ -1,13 +1,15 @@ /* istanbul ignore file */ 'use strict'; const path = require('path'); -const dotenv = require('dotenv'); -const electron = require('electron'); - +let electron; +if (!process.env.STORYBOOK) { + const dotenv = require('dotenv'); + dotenv.config(); + electron = require('electron'); +} const { isDevMode, isTestMode, getSetupFilePath, getUserDataPath } = require('./utils/common'); const pkg = require('../../package.json'); -dotenv.config(); const DEBUG_REQUEST = process.env.DEBUG_REQUEST === '1'; if (DEBUG_REQUEST) { require('request').debug = true; @@ -37,7 +39,7 @@ const DEPOSIT_PRICE_OVERRIDE = process.env.DEPOSIT_PRICE_OVERRIDE; let userDataDirectoryPath = ''; let walletsDirectoryPath = ''; -if (electron.app) { +if (electron && electron.app) { userDataDirectoryPath = electron.app.getPath('userData'); walletsDirectoryPath = path.resolve(userDataDirectoryPath, 'wallets'); } diff --git a/src/common/logger/config.js b/src/common/logger/config.js index 08d51f27c..4b3b3a9c5 100644 --- a/src/common/logger/config.js +++ b/src/common/logger/config.js @@ -57,7 +57,7 @@ export const updateConfig = (conf, silent) => { export const init = () => { updateConfig({}, true); - if (process.env.MODE === 'test') return; + if (process.env.MODE === 'test' || process.env.STORYBOOK) return; if (is.main()) ipcMain.on(LOG_UPDATED_MSG, (event, arg) => updateConfig(arg, true)); else ipcRenderer.on(LOG_UPDATED_MSG, (event, arg) => updateConfig(arg, true)); }; diff --git a/src/common/logger/index.js b/src/common/logger/index.js index 5b93319d8..3340300b2 100644 --- a/src/common/logger/index.js +++ b/src/common/logger/index.js @@ -1,8 +1,15 @@ /* istanbul ignore file */ -import { init as confInit } from './config'; +if (!process.env.STORYBOOK) { + const confInit = require('./config').init; + + confInit(); +} + import Logger from './logger'; -confInit(); +if (process.env.STORYBOOK) { + Logger.prototype.log = console.log.bind(console); +} export const createLog = prefix => new Logger(prefix); diff --git a/src/renderer/attributes/create-attribute-container.js b/src/renderer/attributes/create-attribute-container.js new file mode 100644 index 000000000..05a9bd5d3 --- /dev/null +++ b/src/renderer/attributes/create-attribute-container.js @@ -0,0 +1,57 @@ +import React, { Component } from 'react'; +import { connect } from 'react-redux'; +import { identitySelectors, identityOperations } from 'common/identity'; +import CreateAttribute from './create-attribute'; + +class CreateAttributeContainerComponent extends Component { + handleSave = attribute => { + this.props.dispatch(identityOperations.createIdAttributeOperation(attribute)); + }; + handleCancel = () => { + if (this.props.onClose) return this.props.onClose(); + }; + render() { + let { types, open = true, text, subtitle, uiSchemas, typeId, isDocument } = this.props; + + if (!text) { + if (isDocument) { + text = 'Add Document'; + } else { + text = 'Add Information'; + } + } + + if (!subtitle) { + if (isDocument) { + subtitle = 'Document Type *'; + } else { + subtitle = 'Information Type *'; + } + } + + return ( + + ); + } +} + +const mapStateToProps = (state, props) => { + return { + types: identitySelectors.selectIdAttributeTypes(state, 'individual'), + uiSchemas: identitySelectors.selectUiSchemas(state) + }; +}; + +export const CreateAttributeContainer = connect(mapStateToProps)(CreateAttributeContainerComponent); + +export default CreateAttributeContainer; diff --git a/src/renderer/selfkey-id/main/components/create-attribute.jsx b/src/renderer/attributes/create-attribute.jsx similarity index 94% rename from src/renderer/selfkey-id/main/components/create-attribute.jsx rename to src/renderer/attributes/create-attribute.jsx index 8c764a4f4..4b958b61d 100644 --- a/src/renderer/selfkey-id/main/components/create-attribute.jsx +++ b/src/renderer/attributes/create-attribute.jsx @@ -4,6 +4,7 @@ import { withStyles, Divider, Button, Grid, Select, Typography, Input } from '@m import { identityAttributes, jsonSchema } from 'common/identity/utils'; import Form from 'react-jsonschema-form-material-theme'; import transformErrors from './transform-errors'; +import { Popup } from '../common/popup'; import { KeyboardArrowDown } from '@material-ui/icons'; const styles = theme => ({ @@ -22,6 +23,12 @@ const styles = theme => ({ border: 0, backgroundColor: '#1E262E !important', color: '#FFFFFF !important' + }, + disableTransparency: { + '& > div:first-of-type': { + background: 'linear-gradient(135deg, rgba(43,53,64,1) 0%, rgba(30,38,46,1) 100%)', + opacity: '1 !important' + } } }); @@ -142,13 +149,18 @@ class CreateAttributeComponent extends Component { return this.getTypes(this.props.isDocument, this.props.types); } render() { - const { classes, subtitle } = this.props; + const { classes, subtitle, open, text } = this.props; const types = this.types; const { typeId, label, value, disabled, liveValidate } = this.state; const type = this.type; const uiSchema = this.uiSchema; return ( - +
{subtitle} @@ -248,7 +260,7 @@ class CreateAttributeComponent extends Component {
)} -
+ ); } } diff --git a/src/renderer/selfkey-id/main/containers/delete-attribute-popup.js b/src/renderer/attributes/delete-attribute-container.js similarity index 50% rename from src/renderer/selfkey-id/main/containers/delete-attribute-popup.js rename to src/renderer/attributes/delete-attribute-container.js index 37a4905a0..b241166c0 100644 --- a/src/renderer/selfkey-id/main/containers/delete-attribute-popup.js +++ b/src/renderer/attributes/delete-attribute-container.js @@ -1,10 +1,9 @@ import React, { Component } from 'react'; import { connect } from 'react-redux'; import { identityOperations } from 'common/identity'; -import { Popup } from '../../../common/popup'; -import DeleteAttribute from '../components/delete-attribute'; +import DeleteAttribute from './delete-attribute'; -class DeleteAttributePopupComponent extends Component { +class DeleteAttributeContainerComponent extends Component { handleConfirm = attributeId => { this.props.dispatch(identityOperations.removeIdAttributeOperation(attributeId)); }; @@ -14,18 +13,18 @@ class DeleteAttributePopupComponent extends Component { render() { const { attribute, open = true, text = 'Delete Information and History' } = this.props; return ( - - - + ); } } const mapStateToProps = (state, props) => ({}); -export const DeleteAttributePopup = connect(mapStateToProps)(DeleteAttributePopupComponent); +export const DeleteAttributeContainer = connect(mapStateToProps)(DeleteAttributeContainerComponent); -export default DeleteAttributePopup; +export default DeleteAttributeContainer; diff --git a/src/renderer/selfkey-id/main/components/delete-attribute.jsx b/src/renderer/attributes/delete-attribute.jsx similarity index 100% rename from src/renderer/selfkey-id/main/components/delete-attribute.jsx rename to src/renderer/attributes/delete-attribute.jsx diff --git a/src/renderer/selfkey-id/main/containers/edit-attribute-popup.js b/src/renderer/attributes/edit-attribute-container.js similarity index 59% rename from src/renderer/selfkey-id/main/containers/edit-attribute-popup.js rename to src/renderer/attributes/edit-attribute-container.js index ca2cb84a9..a95472093 100644 --- a/src/renderer/selfkey-id/main/containers/edit-attribute-popup.js +++ b/src/renderer/attributes/edit-attribute-container.js @@ -1,10 +1,9 @@ import React, { PureComponent } from 'react'; import { connect } from 'react-redux'; -import { Popup } from '../../../common/popup'; import { identityOperations, identitySelectors } from 'common/identity'; -import EditAttribute from '../components/edit-attribute'; +import EditAttribute from './edit-attribute'; -class EditAttributePopupComponent extends PureComponent { +class EditAttributeContainerComponent extends PureComponent { handleSave = attribute => { this.props.dispatch(identityOperations.editIdAttributeOperation(attribute)); }; @@ -14,14 +13,14 @@ class EditAttributePopupComponent extends PureComponent { render() { const { open = true, attribute, text = 'Edit Information', uiSchema } = this.props; return ( - - - + ); } } @@ -40,6 +39,6 @@ const mapStateToProps = (state, props) => { uiSchema }; }; -export const EditAttributePopup = connect(mapStateToProps)(EditAttributePopupComponent); +export const EditAttributeContainer = connect(mapStateToProps)(EditAttributeContainerComponent); -export default EditAttributePopup; +export default EditAttributeContainer; diff --git a/src/renderer/selfkey-id/main/components/edit-attribute.jsx b/src/renderer/attributes/edit-attribute.jsx similarity index 95% rename from src/renderer/selfkey-id/main/components/edit-attribute.jsx rename to src/renderer/attributes/edit-attribute.jsx index d5b02141b..2f0564670 100644 --- a/src/renderer/selfkey-id/main/components/edit-attribute.jsx +++ b/src/renderer/attributes/edit-attribute.jsx @@ -1,9 +1,9 @@ import _ from 'lodash'; import React, { Component } from 'react'; import { Input, withStyles, Typography, Divider, Button, Grid } from '@material-ui/core'; -import { identityAttributes } from 'common/identity/utils'; +import { Popup } from '../common/popup'; +import { identityAttributes, jsonSchema } from 'common/identity/utils'; import Form from 'react-jsonschema-form-material-theme'; -import { jsonSchema } from '../../../../common/identity/utils'; import transformErrors from './transform-errors'; const styles = theme => ({ @@ -121,9 +121,9 @@ class EditAttributeComponent extends Component { }; render() { const { type, label, value, schema, title, uiSchema, disabled, liveValidate } = this.state; - const { classes } = this.props; + const { classes, open, text } = this.props; return ( - +
Type @@ -206,7 +206,7 @@ class EditAttributeComponent extends Component {
)} -
+ ); } } diff --git a/src/renderer/attributes/index.js b/src/renderer/attributes/index.js new file mode 100644 index 000000000..28390d939 --- /dev/null +++ b/src/renderer/attributes/index.js @@ -0,0 +1,3 @@ +export { EditAttributeContainer } from './edit-attribute-container'; +export { DeleteAttributeContainer } from './delete-attribute-container'; +export { CreateAttributeContainer } from './create-attribute-container'; diff --git a/src/renderer/selfkey-id/main/components/transform-errors.js b/src/renderer/attributes/transform-errors.js similarity index 100% rename from src/renderer/selfkey-id/main/components/transform-errors.js rename to src/renderer/attributes/transform-errors.js diff --git a/src/renderer/kyc/application/current-application-container.jsx b/src/renderer/kyc/application/current-application-container.jsx index 3afa42c1c..08f3c194c 100644 --- a/src/renderer/kyc/application/current-application-container.jsx +++ b/src/renderer/kyc/application/current-application-container.jsx @@ -2,8 +2,7 @@ import React, { Component } from 'react'; import { connect } from 'react-redux'; import { kycSelectors, kycOperations } from '../../../common/kyc'; import { CurrentApplicationPopup } from './current-application-popup'; -import { CreateAttributePopup } from '../../selfkey-id/main/containers/create-attribute-popup'; -import { EditAttributePopup } from '../../selfkey-id/main/containers/edit-attribute-popup'; +import { CreateAttributeContainer, EditAttributeContainer } from '../../attributes'; import { jsonSchema } from 'common/identity/utils'; import { push } from 'connected-react-router'; import qs from 'query-string'; @@ -122,7 +121,7 @@ class CurrentApplicationComponent extends Component { existingApplicationId={existingApplicationId} /> {this.state.showCreateAttribute && ( - )} {this.state.showEditAttribute && ( - ({ - disableTransparency: { - '& > div:first-of-type': { - background: 'linear-gradient(135deg, rgba(43,53,64,1) 0%, rgba(30,38,46,1) 100%)', - opacity: '1 !important' - } - } -}); - -class CreateAttributePopupComponent extends Component { - handleSave = attribute => { - this.props.dispatch(identityOperations.createIdAttributeOperation(attribute)); - }; - handleCancel = () => { - if (this.props.onClose) return this.props.onClose(); - }; - render() { - let { - classes, - types, - open = true, - text, - subtitle, - uiSchemas, - typeId, - isDocument - } = this.props; - - if (!text) { - if (isDocument) { - text = 'Add Document'; - } else { - text = 'Add Information'; - } - } - - if (!subtitle) { - if (isDocument) { - subtitle = 'Document Type *'; - } else { - subtitle = 'Information Type *'; - } - } - - return ( - - - - ); - } -} - -const mapStateToProps = (state, props) => { - return { - types: identitySelectors.selectIdAttributeTypes(state, 'individual'), - uiSchemas: identitySelectors.selectUiSchemas(state) - }; -}; - -const styledComponent = withStyles(styles)(CreateAttributePopupComponent); -export const CreateAttributePopup = connect(mapStateToProps)(styledComponent); - -export default CreateAttributePopup; diff --git a/src/renderer/selfkey-id/main/containers/selfkey-id-overview.js b/src/renderer/selfkey-id/main/containers/selfkey-id-overview.js index 90278d145..0faa86194 100644 --- a/src/renderer/selfkey-id/main/containers/selfkey-id-overview.js +++ b/src/renderer/selfkey-id/main/containers/selfkey-id-overview.js @@ -3,9 +3,12 @@ import { connect } from 'react-redux'; import { identityOperations } from 'common/identity'; import SelfkeyIdOverview from '../components/selfkey-id-overview'; -import { CreateAttributePopup } from './create-attribute-popup'; -import { EditAttributePopup } from './edit-attribute-popup'; -import { DeleteAttributePopup } from './delete-attribute-popup'; +import { + CreateAttributeContainer, + EditAttributeContainer, + DeleteAttributeContainer +} from '../../../attributes'; + import { EditAvatarPopup } from './edit-avatar-popup'; import { RegisterDidCardContainer } from '../../../did'; @@ -42,21 +45,21 @@ class SelfkeyIdOverviewContainerComponent extends Component { return ( {popup === 'create-attribute' && ( - )} {popup === 'edit-attribute' && ( - )} {popup === 'delete-attribute' && ( - ( + +)); + +storiesOf('Attributes/EditAttribute', module).add('default', () => ( + +)); + +storiesOf('Attributes/DeleteAttribute', module).add('default', () => ( + +)); diff --git a/yarn.lock b/yarn.lock index 77f312af5..22c37f701 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1014,6 +1014,16 @@ resolve "^1.8.1" semver "^5.5.1" +"@babel/plugin-transform-runtime@^7.6.2": + version "7.6.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.6.2.tgz#2669f67c1fae0ae8d8bf696e4263ad52cb98b6f8" + integrity sha512-cqULw/QB4yl73cS5Y0TZlQSjDvNkzDbu0FurTZyHlJpWE5T3PCMdnyV+xXoH1opr1ldyHODe3QAX3OMAii5NxA== + dependencies: + "@babel/helper-module-imports" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + resolve "^1.8.1" + semver "^5.5.1" + "@babel/plugin-transform-shorthand-properties@^7.0.0", "@babel/plugin-transform-shorthand-properties@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.2.0.tgz#6333aee2f8d6ee7e28615457298934a3b46198f0" @@ -3253,16 +3263,16 @@ acorn-walk@^6.0.1: resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-6.1.1.tgz#d363b66f5fac5f018ff9c3a1e7b6f8e310cc3913" integrity sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw== +acorn@6.1.1, acorn@^6.0.1, acorn@^6.0.2, acorn@^6.0.4, acorn@^6.0.5, acorn@^6.0.7: + version "6.1.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.1.1.tgz#7d25ae05bb8ad1f9b699108e1094ecd7884adc1f" + integrity sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA== + acorn@^5.0.0, acorn@^5.5.3, acorn@^5.6.2: version "5.7.3" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279" integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw== -acorn@^6.0.1, acorn@^6.0.2, acorn@^6.0.4, acorn@^6.0.5, acorn@^6.0.7: - version "6.1.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.1.1.tgz#7d25ae05bb8ad1f9b699108e1094ecd7884adc1f" - integrity sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA== - address@1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/address/-/address-1.0.3.tgz#b5f50631f8d6cec8bd20c963963afb55e06cbce9" From f1e0bd883d1b17c470228f738d8d03b109eeb472 Mon Sep 17 00:00:00 2001 From: Andre Goncalves Date: Fri, 27 Sep 2019 15:55:01 +0100 Subject: [PATCH 169/207] fix: storybook, create container --- src/common/identity/selectors.js | 1 - .../corporate/common/corporate-cap-table.jsx | 8 +- .../corporate/common/corporate-details.jsx | 9 +- .../common/corporate-information.jsx | 3 + .../corporate/common/corporate-org-chart.jsx | 8 +- .../dashboard/dashboard-container.jsx | 61 ++-------- .../corporate/dashboard/dashboard-page.jsx | 54 +++++++++ src/renderer/corporate/index.js | 3 +- .../containers/selfkey-id-applications.js | 2 - stories/corporate-data.js | 13 +++ stories/corporate.stories.js | 107 ++++++++++++------ 11 files changed, 174 insertions(+), 95 deletions(-) create mode 100644 src/renderer/corporate/dashboard/dashboard-page.jsx diff --git a/src/common/identity/selectors.js b/src/common/identity/selectors.js index a8f2a6c23..5fc57ed53 100644 --- a/src/common/identity/selectors.js +++ b/src/common/identity/selectors.js @@ -235,7 +235,6 @@ const selectCorporateLegalEntityTypes = state => { }; const selectCurrentCorporateProfile = state => { - console.log(state); const identity = identitySelectors.selectCurrentIdentity(state); return identitySelectors.selectCorporateProfile(state, identity.id); }; diff --git a/src/renderer/corporate/common/corporate-cap-table.jsx b/src/renderer/corporate/common/corporate-cap-table.jsx index 8b88a2c7a..d8a732cef 100644 --- a/src/renderer/corporate/common/corporate-cap-table.jsx +++ b/src/renderer/corporate/common/corporate-cap-table.jsx @@ -27,6 +27,9 @@ const styles = theme => ({ whiteSpace: 'normal', wordBreak: 'break-all' }, + cardAction: { + padding: '1em 1em 0' + }, regularText: { '& span': { fontWeight: 400 @@ -48,7 +51,10 @@ const CorporateCapTable = withStyles(styles)(props => {
diff --git a/src/renderer/corporate/common/corporate-details.jsx b/src/renderer/corporate/common/corporate-details.jsx index d8f0a2b46..654e3f382 100644 --- a/src/renderer/corporate/common/corporate-details.jsx +++ b/src/renderer/corporate/common/corporate-details.jsx @@ -15,6 +15,9 @@ const styles = theme => ({ whiteSpace: 'normal', wordBreak: 'break-all' }, + cardAction: { + padding: '1em 1em 0' + }, regularText: { '& span': { fontWeight: 400 @@ -58,14 +61,16 @@ const editAction = onEdit => ( const CorporateDetails = withStyles(styles)(props => { const { classes, profile, onEdit } = props; - console.log(profile); return (
diff --git a/src/renderer/corporate/common/corporate-information.jsx b/src/renderer/corporate/common/corporate-information.jsx index 3cb60d3e3..3e2395ab8 100644 --- a/src/renderer/corporate/common/corporate-information.jsx +++ b/src/renderer/corporate/common/corporate-information.jsx @@ -35,6 +35,9 @@ const styles = theme => ({ whiteSpace: 'normal', wordBreak: 'break-all' }, + cardAction: { + padding: '20px' + }, regularText: { '& span': { fontWeight: 400 diff --git a/src/renderer/corporate/common/corporate-org-chart.jsx b/src/renderer/corporate/common/corporate-org-chart.jsx index 8097f8120..e0030dfe4 100644 --- a/src/renderer/corporate/common/corporate-org-chart.jsx +++ b/src/renderer/corporate/common/corporate-org-chart.jsx @@ -17,6 +17,9 @@ const styles = theme => ({ whiteSpace: 'normal', wordBreak: 'break-all' }, + cardAction: { + padding: '1em 1em 0' + }, regularText: { '& span': { fontWeight: 400 @@ -78,7 +81,10 @@ const CorporateOrgChart = withStyles(styles)(props => {
diff --git a/src/renderer/corporate/dashboard/dashboard-container.jsx b/src/renderer/corporate/dashboard/dashboard-container.jsx index 7f1e98d82..10a39d68c 100644 --- a/src/renderer/corporate/dashboard/dashboard-container.jsx +++ b/src/renderer/corporate/dashboard/dashboard-container.jsx @@ -1,11 +1,9 @@ import React from 'react'; import { connect } from 'react-redux'; import { identitySelectors } from 'common/identity'; -import { Typography, Grid, withStyles } from '@material-ui/core'; -import { CorporateComponent } from '../common/corporate-component'; -import { CorporateDashboardTabs } from './dashboard-tabs'; +import { CorporateDashboardPage } from './dashboard-page'; -// TODO: replace with real data +// TODO: to be replaced with real data const dummyMembers = [ { id: '1', @@ -78,54 +76,6 @@ const dummyCorporateCapTable = [ } ]; -const styles = theme => ({ - container: { - width: '100%' - }, - title: { - padding: '0' - }, - contentContainer: { - borderBottom: '1px solid #303C49' - } -}); -class CorporateDashboardContainer extends CorporateComponent { - state = { - tab: 'overview' - }; - - onTabChange = tab => this.setState({ tab }); - - render() { - const { classes } = this.props; - const { tab } = this.state; - console.log(this.props); - return ( - - - - SelfKey Corporate Vault - - - - - - - ); - } -} - const mapStateToProps = (state, props) => { return { identity: identitySelectors.selectCurrentIdentity(state), @@ -136,6 +86,9 @@ const mapStateToProps = (state, props) => { }; }; +const CorporateDashboardContainer = connect(mapStateToProps)(props => ( + +)); + const connectedComponent = connect(mapStateToProps)(CorporateDashboardContainer); -const styledComponent = withStyles(styles)(connectedComponent); -export { styledComponent as CorporateDashboardContainer }; +export { connectedComponent as CorporateDashboardContainer }; diff --git a/src/renderer/corporate/dashboard/dashboard-page.jsx b/src/renderer/corporate/dashboard/dashboard-page.jsx new file mode 100644 index 000000000..dc21dd3e7 --- /dev/null +++ b/src/renderer/corporate/dashboard/dashboard-page.jsx @@ -0,0 +1,54 @@ +import React from 'react'; +import { Typography, Grid, withStyles } from '@material-ui/core'; +import { CorporateComponent } from '../common/corporate-component'; +import { CorporateDashboardTabs } from './dashboard-tabs'; + +const styles = theme => ({ + container: { + width: '100%' + }, + title: { + padding: '0' + }, + contentContainer: { + borderBottom: '1px solid #303C49' + } +}); +class CorporateDashboardPage extends CorporateComponent { + state = { + tab: 'overview' + }; + + onTabChange = tab => this.setState({ tab }); + + render() { + const { classes } = this.props; + const { tab } = this.state; + return ( + + + + SelfKey Corporate Vault + + + + + + + ); + } +} + +const styledComponent = withStyles(styles)(CorporateDashboardPage); +export { styledComponent as CorporateDashboardPage }; diff --git a/src/renderer/corporate/index.js b/src/renderer/corporate/index.js index cb0fc9572..73d44a67b 100644 --- a/src/renderer/corporate/index.js +++ b/src/renderer/corporate/index.js @@ -1,3 +1,4 @@ import { CorporateDashboardContainer } from './dashboard/dashboard-container'; +import { CorporateDashboardPage } from './dashboard/dashboard-page'; -export { CorporateDashboardContainer }; +export { CorporateDashboardContainer, CorporateDashboardPage }; diff --git a/src/renderer/selfkey-id/main/containers/selfkey-id-applications.js b/src/renderer/selfkey-id/main/containers/selfkey-id-applications.js index 83124eb42..79634e5b5 100644 --- a/src/renderer/selfkey-id/main/containers/selfkey-id-applications.js +++ b/src/renderer/selfkey-id/main/containers/selfkey-id-applications.js @@ -76,8 +76,6 @@ class SelfkeyIdApplicationsContainerComponent extends Component { return false; } - console.log(rp); - const kycApplication = rp.applications.find(app => app.id === application.id); if (application && kycApplication) { diff --git a/stories/corporate-data.js b/stories/corporate-data.js index f0ae7162f..1868175e9 100644 --- a/stories/corporate-data.js +++ b/stories/corporate-data.js @@ -1,3 +1,16 @@ +export const dummyProfile = { + entityName: 'Selfkey, LLC', + jurisdiction: 'United States', + entityType: 'LLC', + creationDate: '08/08/2018', + address: '1, Amazing Loop, Singapore' +}; +export const dummyIncompleteProfile = { + entityName: 'Selfkey, LLC', + entityType: 'LLC', + creationDate: '08/08/2018' +}; + export const corporateApplications = [ { title: 'Incorporation', diff --git a/stories/corporate.stories.js b/stories/corporate.stories.js index 3bc76e1cd..9ac7aaed9 100644 --- a/stories/corporate.stories.js +++ b/stories/corporate.stories.js @@ -3,7 +3,7 @@ import { action } from '@storybook/addon-actions'; import { linkTo } from '@storybook/addon-links'; import { storiesOf } from '@storybook/react'; -import { CorporateDashboardPage } from '../src/renderer/corporate'; +import { CorporateDashboardPage } from '../src/renderer/corporate/dashboard/dashboard-page'; import { CorporateDashboardTabs } from '../src/renderer/corporate/dashboard/dashboard-tabs'; import { CorporateDetails } from '../src/renderer/corporate/common/corporate-details'; import { CorporateApplicationsSummary } from '../src/renderer/corporate/common/corporate-applications'; @@ -16,6 +16,8 @@ import { CorporateAddMember } from '../src/renderer/corporate/member/corporate-a import { CorporateDocuments } from '../src/renderer/corporate/common/corporate-documents'; import { + dummyProfile, + dummyIncompleteProfile, corporateApplications, corporateCapTable, dummyMembers, @@ -27,89 +29,128 @@ import { storiesOf('Corporate', module).add('Dashboard', () => (
- +
)); storiesOf('Corporate/Dashboard Tabs', module) .add('default', () => ( - tab)} /> + tab)} + /> )) .add('overview', () => ( tab)} /> )) .add('information', () => ( tab)} /> )) .add('members', () => ( tab)} /> )) .add('applications', () => ( tab)} /> )) .add('history', () => ( tab)} /> )); storiesOf('Corporate/Components', module) .add('Company', () => ( - +
+ +
)) .add('Company with missing attributes', () => ( - +
+ +
)) .add('Corporate Applications', () => ( - +
+ +
)) .add('Corporate Cap Table', () => ( - +
+ +
+ )) + .add('Corporate Shareholding', () => ( +
+ +
)) - .add('Corporate Shareholding', () => ) .add('Corporate Org Chart', () => ( - +
+ +
)) .add('Corporate Informations', () => ( - +
+ +
)) .add('Corporate Documents', () => ( - +
+ +
)); storiesOf('Corporate/Wizard', module) From 8de6ad138f4c7484d1dba642ff99634d8d359626 Mon Sep 17 00:00:00 2001 From: Andre Goncalves Date: Fri, 27 Sep 2019 16:09:29 +0100 Subject: [PATCH 170/207] fix: select identity only when new --- src/common/identity/operations.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/identity/operations.js b/src/common/identity/operations.js index 54768426c..f8c483cb8 100644 --- a/src/common/identity/operations.js +++ b/src/common/identity/operations.js @@ -150,8 +150,8 @@ const createCorporateProfileOperation = data => async (dispatch, getState) => { identity = await dispatch( identityOperations.createIdentityOperation(wallet.id, 'corporate') ); + await dispatch(identityOperations.setCurrentIdentityAction(identity.id)); } - await dispatch(identityOperations.setCurrentIdentityAction(identity.id)); const getTypeId = url => { return idAttributeTypes.find(idAttributeType => idAttributeType.url === url).id; }; From 60249568fd0212b8f3748738047c0e68c3c9e9e6 Mon Sep 17 00:00:00 2001 From: Maxim Kovalov Date: Sat, 28 Sep 2019 14:26:24 +0300 Subject: [PATCH 171/207] feat(corp): wire up information tab --- src/common/identity/selectors.js | 4 +- .../attributes/create-attribute-container.js | 5 +- src/renderer/attributes/delete-attribute.jsx | 96 +++++++++++-------- .../corporate/common/corporate-documents.jsx | 4 +- .../common/corporate-information.jsx | 4 +- .../dashboard/dashboard-container.jsx | 79 ++++++++++++++- .../corporate/dashboard/dashboard-page.jsx | 2 +- .../corporate/dashboard/dashboard-tabs.jsx | 53 ++++++---- .../corporate/dashboard/information-tab.jsx | 52 +++++++++- stories/corporate.stories.js | 8 ++ 10 files changed, 228 insertions(+), 79 deletions(-) diff --git a/src/common/identity/selectors.js b/src/common/identity/selectors.js index 5fc57ed53..e42e6c5da 100644 --- a/src/common/identity/selectors.js +++ b/src/common/identity/selectors.js @@ -257,9 +257,7 @@ const selectCorporateProfile = (state, id) => { }, { seen: {}, attrs: [] } ).attrs; - const attributes = allAttributes.filter( - attr => !jsonSchema.containsFile(attr.type.content) && !basicAttributes.includes(attr) - ); + const attributes = allAttributes.filter(attr => !jsonSchema.containsFile(attr.type.content)); // FIXME: document type should be determined by attribute type const documents = allAttributes.filter(attr => jsonSchema.containsFile(attr.type.content)); diff --git a/src/renderer/attributes/create-attribute-container.js b/src/renderer/attributes/create-attribute-container.js index 05a9bd5d3..aa4c81517 100644 --- a/src/renderer/attributes/create-attribute-container.js +++ b/src/renderer/attributes/create-attribute-container.js @@ -47,7 +47,10 @@ class CreateAttributeContainerComponent extends Component { const mapStateToProps = (state, props) => { return { - types: identitySelectors.selectIdAttributeTypes(state, 'individual'), + types: identitySelectors.selectIdAttributeTypes( + state, + props.corporate ? 'corporate' : 'individual' + ), uiSchemas: identitySelectors.selectUiSchemas(state) }; }; diff --git a/src/renderer/attributes/delete-attribute.jsx b/src/renderer/attributes/delete-attribute.jsx index 72e395d06..8669445e3 100644 --- a/src/renderer/attributes/delete-attribute.jsx +++ b/src/renderer/attributes/delete-attribute.jsx @@ -1,6 +1,7 @@ import React, { Component } from 'react'; import { Input, Typography, withStyles, Button, Grid } from '@material-ui/core'; +import { Popup } from '../common/popup'; const styles = theme => ({ text: { @@ -30,55 +31,66 @@ class DeleteAttributeComponent extends Component { this.props.onCancel(); }; render() { - const { attribute, classes } = this.props; + const { attribute, classes, open, text } = this.props; const { type, name } = attribute; return ( - - - - You are deleting this information and all related history. Once deleted, you{' '} - can not recover the history. - - - Type - - - - Label - - - - - - - - + + + + + You are deleting this information and all related history. Once deleted, + you can not recover the history. + + + Type + + + + Label + + + + + + + + - - + + + - + ); } } diff --git a/src/renderer/corporate/common/corporate-documents.jsx b/src/renderer/corporate/common/corporate-documents.jsx index de73d69e5..1a8df48b2 100644 --- a/src/renderer/corporate/common/corporate-documents.jsx +++ b/src/renderer/corporate/common/corporate-documents.jsx @@ -12,7 +12,8 @@ import { TableHead, TableBody, IconButton, - Button + Button, + withStyles } from '@material-ui/core'; import { SmallTableHeadRow, @@ -24,7 +25,6 @@ import { FileMultipleIcon, FileAudioIcon } from 'selfkey-ui'; -import { withStyles } from '@material-ui/core'; const styles = theme => ({ hr: { diff --git a/src/renderer/corporate/common/corporate-information.jsx b/src/renderer/corporate/common/corporate-information.jsx index 3e2395ab8..7ad25d05b 100644 --- a/src/renderer/corporate/common/corporate-information.jsx +++ b/src/renderer/corporate/common/corporate-information.jsx @@ -10,7 +10,8 @@ import { TableHead, TableBody, IconButton, - Button + Button, + withStyles } from '@material-ui/core'; import { IdCardIcon, @@ -20,7 +21,6 @@ import { EditTransparentIcon, DeleteIcon } from 'selfkey-ui'; -import { withStyles } from '@material-ui/core'; const styles = theme => ({ hr: { diff --git a/src/renderer/corporate/dashboard/dashboard-container.jsx b/src/renderer/corporate/dashboard/dashboard-container.jsx index 10a39d68c..fe78a946e 100644 --- a/src/renderer/corporate/dashboard/dashboard-container.jsx +++ b/src/renderer/corporate/dashboard/dashboard-container.jsx @@ -1,7 +1,12 @@ -import React from 'react'; +import React, { Component } from 'react'; import { connect } from 'react-redux'; -import { identitySelectors } from 'common/identity'; +import { identitySelectors, identityOperations } from 'common/identity'; import { CorporateDashboardPage } from './dashboard-page'; +import { + CreateAttributeContainer, + EditAttributeContainer, + DeleteAttributeContainer +} from '../../attributes'; // TODO: to be replaced with real data const dummyMembers = [ @@ -86,9 +91,73 @@ const mapStateToProps = (state, props) => { }; }; -const CorporateDashboardContainer = connect(mapStateToProps)(props => ( - -)); +class CorporateDashboardContainer extends Component { + state = { + popup: null + }; + + handleAttributeDelete = attributeId => + this.props.dispatch(identityOperations.removeIdAttributeOperation(attributeId)); + + handleEditAttribute = attribute => { + this.setState({ popup: 'edit-attribute', editAttribute: attribute }); + }; + handleAddAttribute = () => { + this.setState({ popup: 'create-attribute', isDocument: false }); + }; + handleAddDocument = () => { + this.setState({ popup: 'create-attribute', isDocument: true }); + }; + handleDeleteAttribute = attribute => { + this.setState({ popup: 'delete-attribute', deleteAttribute: attribute }); + }; + handlePopupClose = () => { + this.setState({ popup: null }); + }; + + render() { + const { popup } = this.state; + + return ( + + {popup === 'create-attribute' && ( + + )} + {popup === 'edit-attribute' && ( + + )} + {popup === 'delete-attribute' && ( + + )} + + + + ); + } +} const connectedComponent = connect(mapStateToProps)(CorporateDashboardContainer); export { connectedComponent as CorporateDashboardContainer }; diff --git a/src/renderer/corporate/dashboard/dashboard-page.jsx b/src/renderer/corporate/dashboard/dashboard-page.jsx index dc21dd3e7..61e47bae7 100644 --- a/src/renderer/corporate/dashboard/dashboard-page.jsx +++ b/src/renderer/corporate/dashboard/dashboard-page.jsx @@ -38,7 +38,7 @@ class CorporateDashboardPage extends CorporateComponent { SelfKey Corporate Vault - + ({}); export const CorporateDashboardTabs = withStyles(styles)( ({ classes, tab = 'overview', onTabChange, ...tabProps }) => { return ( - - onTabChange(value)}> - - - - - - - - {tab === 'overview' && } - {tab === 'information' && ( - - )} - {tab === 'members' && } - {tab === 'applications' && ( - - )} - {tab === 'history' && } - + + + onTabChange(value)}> + + + + + + + + + {tab === 'overview' && } + {tab === 'information' && ( + + )} + {tab === 'members' && } + {tab === 'applications' && ( + + )} + {tab === 'history' && } + + ); } ); diff --git a/src/renderer/corporate/dashboard/information-tab.jsx b/src/renderer/corporate/dashboard/information-tab.jsx index d9e8d0836..4b4284709 100644 --- a/src/renderer/corporate/dashboard/information-tab.jsx +++ b/src/renderer/corporate/dashboard/information-tab.jsx @@ -1,9 +1,55 @@ import React from 'react'; -import { withStyles } from '@material-ui/core'; +import { withStyles, Grid } from '@material-ui/core'; +import { CorporateInformation } from '../common/corporate-information'; +import { CorporateDocuments } from '../common/corporate-documents'; -const styles = theme => ({}); +const styles = theme => ({ + container: { + padding: '20px', + width: '100%' + } +}); -const CorporateInformationTab = withStyles(styles)(({ classes }) =>
); +const CorporateInformationTab = withStyles(styles)( + ({ + classes, + attributes, + onAddAttribute, + onEditAttribute, + onDeleteAttribute, + documents, + onAddDocument, + onEditDocument, + onDeleteDocument + }) => ( +
+ + + + + + + + +
+ ) +); export { CorporateInformationTab }; export default CorporateInformationTab; diff --git a/stories/corporate.stories.js b/stories/corporate.stories.js index 9ac7aaed9..53a85af3f 100644 --- a/stories/corporate.stories.js +++ b/stories/corporate.stories.js @@ -62,6 +62,14 @@ storiesOf('Corporate/Dashboard Tabs', module) cap={corporateCapTable} applications={corporateApplications} onTabChange={linkTo('Corporate/Dashboard Tabs', tab => tab)} + attributes={corporateAttributes} + onEditAttribute={action('on edit attribute')} + onDeleteAttribute={action('on delete attribute')} + onAddAttribute={action('on add attribute')} + documents={corporateDocuments} + onAddDocument={action('on add document')} + onEditDocument={action('on edit document')} + onDeleteDocument={action('on delete document')} /> )) .add('members', () => ( From acc8984c0e0d3fe2b06cced20304bbbabf40fbfd Mon Sep 17 00:00:00 2001 From: Maxim Kovalov Date: Mon, 30 Sep 2019 06:51:14 +0300 Subject: [PATCH 172/207] fix(did): associate did --- src/common/did/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/common/did/index.js b/src/common/did/index.js index 2c0d7c0b1..1d382bb1b 100644 --- a/src/common/did/index.js +++ b/src/common/did/index.js @@ -66,8 +66,8 @@ const createDIDOperation = () => async (dispatch, getState) => { const didService = getGlobalContext().didService; await dispatch(didActions.setDidPending(identity.id, true)); - const gasLimit = await didService.getGasLimit(walletFromStore.publicKey); - const transaction = didService.createDID(walletFromStore.publicKey, gasLimit); + const gasLimit = await didService.getGasLimit(walletFromStore.address); + const transaction = didService.createDID(walletFromStore.address, gasLimit); transaction.on('receipt', async receipt => { const did = receipt.events.CreatedDID.returnValues.id; const identityService = getGlobalContext().identityService; @@ -121,7 +121,7 @@ const updateDIDOperation = did => async (dispatch, getState) => { let identity = identitySelectors.selectCurrentIdentity(getState()); const DIDService = getGlobalContext().didService; const controllerAddress = await DIDService.getControllerAddress(did); - if (walletFromStore.publicKey.toLowerCase() === controllerAddress.toLowerCase()) { + if (walletFromStore.address.toLowerCase() === controllerAddress.toLowerCase()) { const identityService = getGlobalContext().identityService; identity = await identityService.updateIdentityDID(did, identity.id); await dispatch(identityOperations.updateIdentity(identity)); From 7e0b92804895c61af62db7227a553754ee58d312 Mon Sep 17 00:00:00 2001 From: Maxim Kovalov Date: Mon, 30 Sep 2019 08:38:42 +0300 Subject: [PATCH 173/207] fix(corporate): fix corporate dashboard layout --- .../common/corporate-applications.jsx | 84 ++++---- .../corporate/common/corporate-cap-table.jsx | 147 +++++++------- .../corporate/common/corporate-details.jsx | 94 +++++---- .../corporate/common/corporate-documents.jsx | 188 ++++++++---------- .../common/corporate-information.jsx | 175 ++++++++-------- .../corporate/dashboard/dashboard-tabs.jsx | 2 +- .../corporate/dashboard/information-tab.jsx | 6 +- .../corporate/dashboard/overview-tab.jsx | 86 ++++---- stories/corporate-data.js | 3 + 9 files changed, 374 insertions(+), 411 deletions(-) diff --git a/src/renderer/corporate/common/corporate-applications.jsx b/src/renderer/corporate/common/corporate-applications.jsx index 42cd7335a..aad8918c0 100644 --- a/src/renderer/corporate/common/corporate-applications.jsx +++ b/src/renderer/corporate/common/corporate-applications.jsx @@ -63,55 +63,49 @@ const renderStatus = status => { const CorporateApplicationsSummary = withStyles(styles)(props => { const { classes, applications = [] } = props; return ( - - - - -
- - - - - + + +
+ + +
+ + + + Service + + + Provider + + + Status + + + + + {applications && + applications.map(a => ( + - Service + {a.title} - Provider + {a.rpName} - - Status - - - - - {applications && - applications.map(a => ( - - - {a.title} - - - {a.rpName} - - - {renderStatus(a.currentStatusName)} - - - ))} - -
-
-
-
-
-
+ {renderStatus(a.currentStatusName)} + + ))} + + + + + ); }); diff --git a/src/renderer/corporate/common/corporate-cap-table.jsx b/src/renderer/corporate/common/corporate-cap-table.jsx index d8a732cef..265d6baa5 100644 --- a/src/renderer/corporate/common/corporate-cap-table.jsx +++ b/src/renderer/corporate/common/corporate-cap-table.jsx @@ -22,7 +22,9 @@ const styles = theme => ({ height: '1px', margin: '5px 16px' }, - card: {}, + card: { + height: '100%' + }, cardHeader: { whiteSpace: 'normal', wordBreak: 'break-all' @@ -46,96 +48,87 @@ const editAction = onEdit => ( const CorporateCapTable = withStyles(styles)(props => { const { classes, cap = [], onEdit } = props; return ( - - - - -
- - - - - + + +
+ + +
+ + + + Type + + + Role + + + Name + + + Email + + + + Citizenship / Incorporation + + + + Residency / Domicile + + + Shares + + + + + {cap && + cap.map((c, idx) => ( + - Type + {c.type} - Role + {c.role} - Name + {c.name} - Email + + {c.email ? c.email : '-'} + - - Citizenship / Incorporation - + {c.citizenship} - - Residency / Domicile - + {c.residency} - Shares + {c.shares} - - - - {cap && - cap.map((c, idx) => ( - - - {c.type} - - - {c.role} - - - {c.name} - - - - {c.email ? c.email : '-'} - - - - - {c.citizenship} - - - - - {c.residency} - - - - {c.shares} - - - ))} - -
-
-
-
-
-
+ + ))} + + + + + ); }); diff --git a/src/renderer/corporate/common/corporate-details.jsx b/src/renderer/corporate/common/corporate-details.jsx index 654e3f382..6c5155f05 100644 --- a/src/renderer/corporate/common/corporate-details.jsx +++ b/src/renderer/corporate/common/corporate-details.jsx @@ -62,55 +62,51 @@ const editAction = onEdit => ( const CorporateDetails = withStyles(styles)(props => { const { classes, profile, onEdit } = props; return ( - - - - -
- - -
- - Jurisdiction - - {renderAttr(profile.jurisdiction)} -
-
- - Entity Type - - {renderAttr(profile.entityType)} -
-
- - Incorporation Date - - {renderAttr(profile.creationDate)} -
-
- - Address - - {renderAttr(profile.address)} -
-
-
-
-
-
+ + +
+ + +
+ + Jurisdiction + + {renderAttr(profile.jurisdiction)} +
+
+ + Entity Type + + {renderAttr(profile.entityType)} +
+
+ + Incorporation Date + + {renderAttr(profile.creationDate)} +
+
+ + Address + + {renderAttr(profile.address)} +
+
+
+
); }); diff --git a/src/renderer/corporate/common/corporate-documents.jsx b/src/renderer/corporate/common/corporate-documents.jsx index 1a8df48b2..56bdd2d5f 100644 --- a/src/renderer/corporate/common/corporate-documents.jsx +++ b/src/renderer/corporate/common/corporate-documents.jsx @@ -127,107 +127,95 @@ const DocumentExpiryDate = ({ doc }) => { const CorporateDocuments = withStyles(styles)(props => { const { classes, documents = [], onEditDocument, onDeleteDocument, onAddDocument } = props; return ( - - - - -
- - - - - - - - - Type - - - - Label - - - - - Expiry Date - - - - - Last Edited - - - - - Actions - - - - - - {documents.map(entry => ( - - - - {renderAttributeTitle(entry)} - - - - {renderDocumentName({ entry, classes })} - - - - - - - {renderLastUpdateDate(entry)} - - - - onEditDocument(entry)} - > - - - onDeleteDocument(entry)} - > - - - - - ))} - -
-
-
- - - - - + + +
+ + + + + + + + + Type + + + Label + + + Expiry Date + + + Last Edited + + + Actions + + + + + {documents.map(entry => ( + + + + {renderAttributeTitle(entry)} + + + + {renderDocumentName({ entry, classes })} + + + + + + + {renderLastUpdateDate(entry)} + + + + onEditDocument(entry)} + > + + + onDeleteDocument(entry)} + > + + + + + ))} + +
+
+
+ + + -
-
-
-
+
+ + + ); }); diff --git a/src/renderer/corporate/common/corporate-information.jsx b/src/renderer/corporate/common/corporate-information.jsx index 7ad25d05b..fc434e97f 100644 --- a/src/renderer/corporate/common/corporate-information.jsx +++ b/src/renderer/corporate/common/corporate-information.jsx @@ -71,24 +71,23 @@ const renderAttributeTitle = attr => attr.type.content.title || 'No title provid const CorporateInformation = withStyles(styles)(props => { const { classes, attributes = [], onEditAttribute, onDeleteAttribute, onAddAttribute } = props; return ( - - - - -
- - - + + +
+ + + + + { - - - - - - - Information + + +
+ + + + + Information + + + + Label + + + + Last edited + + + + Actions + + + + + {attributes.map(attr => ( + + + + {renderAttributeTitle(attr)} - - - Label + + + {renderAttributeValue(attr)} - - - Last edited + + + {renderLastUpdateDate(attr)} - - - Actions - + + onEditAttribute(attr)} + > + + + onDeleteAttribute(attr)} + > + + - - - - {attributes.map(attr => ( - - - - {renderAttributeTitle(attr)} - - - - - {renderAttributeValue(attr)} - - - - - {renderLastUpdateDate(attr)} - - - - onEditAttribute(attr)} - > - - - onDeleteAttribute(attr)} - > - - - - - ))} - -
-
+ + ))} + +
- - - - + +
+ + + + -
-
-
-
+
+
+ + ); }); diff --git a/src/renderer/corporate/dashboard/dashboard-tabs.jsx b/src/renderer/corporate/dashboard/dashboard-tabs.jsx index 54c7d6ef1..38bb50c53 100644 --- a/src/renderer/corporate/dashboard/dashboard-tabs.jsx +++ b/src/renderer/corporate/dashboard/dashboard-tabs.jsx @@ -16,7 +16,7 @@ export const CorporateDashboardTabs = withStyles(styles)( direction="column" justify="flex-start" alignItems="stretch" - spacing={4} + spacing={8} > onTabChange(value)}> diff --git a/src/renderer/corporate/dashboard/information-tab.jsx b/src/renderer/corporate/dashboard/information-tab.jsx index 4b4284709..4c488d1f4 100644 --- a/src/renderer/corporate/dashboard/information-tab.jsx +++ b/src/renderer/corporate/dashboard/information-tab.jsx @@ -6,7 +6,9 @@ import { CorporateDocuments } from '../common/corporate-documents'; const styles = theme => ({ container: { padding: '20px', - width: '100%' + width: '100%', + boxSizing: 'border-box', + position: 'relative' } }); @@ -28,7 +30,7 @@ const CorporateInformationTab = withStyles(styles)( direction="column" justify="flex-start" alignItems="stretch" - spacing={4} + spacing={16} > ({ - flexGrow: { - flexGrow: 1, - width: '100%', - maxWidth: '100%', - overflow: 'hidden' - }, - CorporateShareholding: { - width: '550px' - } -}); +const styles = theme => ({}); const CorporateOverviewTab = withStyles(styles)(({ classes, applications, profile, cap }) => (
- - - + + + + + + + + + + - - - - - - + - - - - - - - + + + + + + + + +
diff --git a/stories/corporate-data.js b/stories/corporate-data.js index 1868175e9..39db97b59 100644 --- a/stories/corporate-data.js +++ b/stories/corporate-data.js @@ -13,16 +13,19 @@ export const dummyIncompleteProfile = { export const corporateApplications = [ { + id: 1, title: 'Incorporation', rpName: 'Flag Theory', currentStatusName: 'pending' }, { + id: 2, title: 'Banking', rpName: 'Flag Theory', currentStatusName: 'rejected' }, { + id: 3, title: 'Banking', rpName: 'Bank of China', currentStatusName: 'approved' From 57343ea707af9ea870db702488244df0e922ebb8 Mon Sep 17 00:00:00 2001 From: Maxim Kovalov Date: Mon, 30 Sep 2019 08:40:24 +0300 Subject: [PATCH 174/207] fix(corporate): fix corporate dashboard layout --- .../corporate/dashboard/information-tab.jsx | 51 +++++++------------ 1 file changed, 18 insertions(+), 33 deletions(-) diff --git a/src/renderer/corporate/dashboard/information-tab.jsx b/src/renderer/corporate/dashboard/information-tab.jsx index 4c488d1f4..5b8630605 100644 --- a/src/renderer/corporate/dashboard/information-tab.jsx +++ b/src/renderer/corporate/dashboard/information-tab.jsx @@ -3,14 +3,7 @@ import { withStyles, Grid } from '@material-ui/core'; import { CorporateInformation } from '../common/corporate-information'; import { CorporateDocuments } from '../common/corporate-documents'; -const styles = theme => ({ - container: { - padding: '20px', - width: '100%', - boxSizing: 'border-box', - position: 'relative' - } -}); +const styles = theme => ({}); const CorporateInformationTab = withStyles(styles)( ({ @@ -24,32 +17,24 @@ const CorporateInformationTab = withStyles(styles)( onEditDocument, onDeleteDocument }) => ( -
- - - - - - - + + + -
+ + + +
) ); From 837c849e44be9d6fe5bb16a0656bdb6b3e25a905 Mon Sep 17 00:00:00 2001 From: Maxim Kovalov Date: Mon, 30 Sep 2019 08:55:50 +0300 Subject: [PATCH 175/207] fix(corporate): fix corporate dashboard layout --- src/renderer/corporate/dashboard/dashboard-container.jsx | 6 ++++++ src/renderer/corporate/dashboard/overview-tab.jsx | 8 ++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/renderer/corporate/dashboard/dashboard-container.jsx b/src/renderer/corporate/dashboard/dashboard-container.jsx index fe78a946e..35ad7d703 100644 --- a/src/renderer/corporate/dashboard/dashboard-container.jsx +++ b/src/renderer/corporate/dashboard/dashboard-container.jsx @@ -96,6 +96,12 @@ class CorporateDashboardContainer extends Component { popup: null }; + componentDidUpdate() { + if (this.props.identity.type !== 'corporate') { + this.props.dispatch(identityOperations.navigateToProfileOperation()); + } + } + handleAttributeDelete = attributeId => this.props.dispatch(identityOperations.removeIdAttributeOperation(attributeId)); diff --git a/src/renderer/corporate/dashboard/overview-tab.jsx b/src/renderer/corporate/dashboard/overview-tab.jsx index 457529230..6c5efb94e 100644 --- a/src/renderer/corporate/dashboard/overview-tab.jsx +++ b/src/renderer/corporate/dashboard/overview-tab.jsx @@ -6,7 +6,11 @@ import { CorporateCapTable } from '../common/corporate-cap-table'; import { CorporateShareholding } from '../common/corporate-shareholding'; import { CorporateOrgChart } from '../common/corporate-org-chart'; -const styles = theme => ({}); +const styles = theme => ({ + corporateShareholding: { + width: '550px' + } +}); const CorporateOverviewTab = withStyles(styles)(({ classes, applications, profile, cap }) => (
@@ -43,7 +47,7 @@ const CorporateOverviewTab = withStyles(styles)(({ classes, applications, profil wrap="nowrap" spacing={16} > - + From 0f195879e0bb9c7d846761ce1255606d0bc47fb2 Mon Sep 17 00:00:00 2001 From: Andre Goncalves Date: Mon, 30 Sep 2019 10:29:35 +0100 Subject: [PATCH 176/207] fix: object type attributes --- .../corporate/common/corporate-details.jsx | 10 ++- .../common/corporate-information.jsx | 14 ++- .../corporate/dashboard/dashboard-page.jsx | 3 + .../corporate/dashboard/overview-tab.jsx | 90 ++++++++++--------- 4 files changed, 74 insertions(+), 43 deletions(-) diff --git a/src/renderer/corporate/common/corporate-details.jsx b/src/renderer/corporate/common/corporate-details.jsx index 6c5155f05..fda369f17 100644 --- a/src/renderer/corporate/common/corporate-details.jsx +++ b/src/renderer/corporate/common/corporate-details.jsx @@ -53,6 +53,14 @@ const renderAttr = attr => ); +const renderAddressAtr = profile => { + const addressAtr = profile.allAttributes.find(a => a.name === 'Address'); + if (addressAtr) { + const value = addressAtr.data.value; + return renderAttr(!value ? `${value.address_line_1} ${value.address_line_2}` : ''); + } else return renderAttr(''); +}; + const editAction = onEdit => (
@@ -102,7 +110,7 @@ const CorporateDetails = withStyles(styles)(props => { Address - {renderAttr(profile.address)} + {renderAddressAtr(profile)}
diff --git a/src/renderer/corporate/common/corporate-information.jsx b/src/renderer/corporate/common/corporate-information.jsx index fc434e97f..04e5bd23e 100644 --- a/src/renderer/corporate/common/corporate-information.jsx +++ b/src/renderer/corporate/common/corporate-information.jsx @@ -64,7 +64,19 @@ const renderLastUpdateDate = ({ updatedAt }) => moment(updatedAt).format('DD MMM // const renderAttributeLabel = ({ name }) => name || 'No label provided'; -const renderAttributeValue = ({ data }) => data.value || ''; +const renderAttributeValue = ({ data, type }) => { + let valueToString = ''; + if (type.content.type === 'object') { + for (const prop in data.value) { + if (Object.prototype.hasOwnProperty.call(data.value, prop)) { + valueToString += `${data.value[prop]} `; + } + } + } else { + valueToString = data.value || ''; + } + return valueToString.trim(); +}; const renderAttributeTitle = attr => attr.type.content.title || 'No title provided'; diff --git a/src/renderer/corporate/dashboard/dashboard-page.jsx b/src/renderer/corporate/dashboard/dashboard-page.jsx index 61e47bae7..5d24d2c02 100644 --- a/src/renderer/corporate/dashboard/dashboard-page.jsx +++ b/src/renderer/corporate/dashboard/dashboard-page.jsx @@ -21,6 +21,8 @@ class CorporateDashboardPage extends CorporateComponent { onTabChange = tab => this.setState({ tab }); + onEditCorporateDetails = () => this.setState({ tab: 'information' }); + render() { const { classes } = this.props; const { tab } = this.state; @@ -41,6 +43,7 @@ class CorporateDashboardPage extends CorporateComponent { diff --git a/src/renderer/corporate/dashboard/overview-tab.jsx b/src/renderer/corporate/dashboard/overview-tab.jsx index 6c5efb94e..7b4ddaee9 100644 --- a/src/renderer/corporate/dashboard/overview-tab.jsx +++ b/src/renderer/corporate/dashboard/overview-tab.jsx @@ -12,52 +12,60 @@ const styles = theme => ({ } }); -const CorporateOverviewTab = withStyles(styles)(({ classes, applications, profile, cap }) => ( -
- - - - - - - - +const CorporateOverviewTab = withStyles(styles)( + ({ classes, applications, profile, cap, onEditCorporateDetails }) => ( +
+ + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - -
-)); +
+ ) +); export { CorporateOverviewTab }; export default CorporateOverviewTab; From d7aed5d29d8d1b0489c6e479b05f9832c5435723 Mon Sep 17 00:00:00 2001 From: Maxim Kovalov Date: Mon, 30 Sep 2019 13:23:06 +0300 Subject: [PATCH 177/207] fix(wallet-token): remove address from eth wallet-token --- src/common/wallet-tokens/selectors.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/common/wallet-tokens/selectors.js b/src/common/wallet-tokens/selectors.js index 4fb8c9b0e..71da0989e 100644 --- a/src/common/wallet-tokens/selectors.js +++ b/src/common/wallet-tokens/selectors.js @@ -7,6 +7,7 @@ export const getTopTokenListSize = state => state.walletTokens.topTokenListSize; export const getTokens = state => { const tokens = state.walletTokens.tokens.slice(0); + const wallet = { ...getWallet(state) }; tokens.forEach(token => { const price = getPrices(state).prices.filter(price => price.symbol === token.symbol)[0]; const priceUSD = price ? price.priceUSD : 0; @@ -15,7 +16,8 @@ export const getTokens = state => { // Workaround for Tokens with different Symbols than the ones in price table token.name = token.name ? token.name : 'Token'; }); - return [getWallet(state), ...tokens]; + delete wallet.address; + return [wallet, ...tokens]; }; const getTokensForDisplay = state => { From d81b9cb2771e1e5a8fcf5759a23dc0b6524b5c7c Mon Sep 17 00:00:00 2001 From: Andre Goncalves Date: Tue, 1 Oct 2019 10:19:32 +0100 Subject: [PATCH 178/207] feat: add did to corporate dashboard, refactor corp stories --- .../corporate/common/corporate-details.jsx | 8 +++++++ .../dashboard/dashboard-container.jsx | 5 +++- .../corporate/dashboard/overview-tab.jsx | 3 ++- .../did/register-did-card-container.js | 12 ++++++++-- stories/corporate-data.js | 8 +++++-- stories/corporate.stories.js | 23 ++++++++++++++++++- 6 files changed, 52 insertions(+), 7 deletions(-) diff --git a/src/renderer/corporate/common/corporate-details.jsx b/src/renderer/corporate/common/corporate-details.jsx index fda369f17..8e4729944 100644 --- a/src/renderer/corporate/common/corporate-details.jsx +++ b/src/renderer/corporate/common/corporate-details.jsx @@ -112,6 +112,14 @@ const CorporateDetails = withStyles(styles)(props => { {renderAddressAtr(profile)}
+ {profile.did && ( +
+ + DID + + {profile.did} +
+ )}
diff --git a/src/renderer/corporate/dashboard/dashboard-container.jsx b/src/renderer/corporate/dashboard/dashboard-container.jsx index 35ad7d703..3b2f389f5 100644 --- a/src/renderer/corporate/dashboard/dashboard-container.jsx +++ b/src/renderer/corporate/dashboard/dashboard-container.jsx @@ -2,6 +2,7 @@ import React, { Component } from 'react'; import { connect } from 'react-redux'; import { identitySelectors, identityOperations } from 'common/identity'; import { CorporateDashboardPage } from './dashboard-page'; +import { RegisterDidCardContainer } from '../../did'; import { CreateAttributeContainer, EditAttributeContainer, @@ -123,7 +124,6 @@ class CorporateDashboardContainer extends Component { render() { const { popup } = this.state; - return ( {popup === 'create-attribute' && ( @@ -159,6 +159,9 @@ class CorporateDashboardContainer extends Component { onAddDocument={this.handleAddDocument} onEditDocument={this.handleEditAttribute} onDeleteDocument={this.handleDeleteAttribute} + didComponent={ + + } /> ); diff --git a/src/renderer/corporate/dashboard/overview-tab.jsx b/src/renderer/corporate/dashboard/overview-tab.jsx index 7b4ddaee9..ba3819f86 100644 --- a/src/renderer/corporate/dashboard/overview-tab.jsx +++ b/src/renderer/corporate/dashboard/overview-tab.jsx @@ -13,7 +13,7 @@ const styles = theme => ({ }); const CorporateOverviewTab = withStyles(styles)( - ({ classes, applications, profile, cap, onEditCorporateDetails }) => ( + ({ classes, applications, profile, cap, onEditCorporateDetails, didComponent }) => (
+ {!profile.did && {didComponent}} - this.props.dispatch(didOperations.startCreateDidFlowOperation(SELFKEY_ID_PATH)); + this.props.dispatch( + didOperations.startCreateDidFlowOperation( + this.props.returnPath ? this.props.returnPath : SELFKEY_ID_PATH + ) + ); handleAssociateDidClick = _ => - this.props.dispatch(didOperations.startAssociateDidFlowOperation(SELFKEY_ID_PATH)); + this.props.dispatch( + didOperations.startAssociateDidFlowOperation( + this.props.returnPath ? this.props.returnPath : SELFKEY_ID_PATH + ) + ); render() { return ( diff --git a/stories/corporate-data.js b/stories/corporate-data.js index 39db97b59..b0963b0ff 100644 --- a/stories/corporate-data.js +++ b/stories/corporate-data.js @@ -3,12 +3,16 @@ export const dummyProfile = { jurisdiction: 'United States', entityType: 'LLC', creationDate: '08/08/2018', - address: '1, Amazing Loop, Singapore' + address: '1, Amazing Loop, Singapore', + did: 'did:selfkey:0x9cb701490ad6112d2880225c1d712f1af8c7dce1a81c44030b321fb31029cd75', + allAttributes: [] }; export const dummyIncompleteProfile = { entityName: 'Selfkey, LLC', entityType: 'LLC', - creationDate: '08/08/2018' + creationDate: '08/08/2018', + did: false, + allAttributes: [] }; export const corporateApplications = [ diff --git a/stories/corporate.stories.js b/stories/corporate.stories.js index 53a85af3f..759c21a0e 100644 --- a/stories/corporate.stories.js +++ b/stories/corporate.stories.js @@ -3,6 +3,8 @@ import { action } from '@storybook/addon-actions'; import { linkTo } from '@storybook/addon-links'; import { storiesOf } from '@storybook/react'; +import { RegisterDidCard } from '../src/renderer/did/register-did-card'; + import { CorporateDashboardPage } from '../src/renderer/corporate/dashboard/dashboard-page'; import { CorporateDashboardTabs } from '../src/renderer/corporate/dashboard/dashboard-tabs'; import { CorporateDetails } from '../src/renderer/corporate/common/corporate-details'; @@ -55,6 +57,21 @@ storiesOf('Corporate/Dashboard Tabs', module) onTabChange={linkTo('Corporate/Dashboard Tabs', tab => tab)} /> )) + .add('overview with incomplete profile', () => ( + + } + onTabChange={linkTo('Corporate/Dashboard Tabs', tab => tab)} + /> + )) .add('information', () => ( (
- +
)) .add('Corporate Informations', () => ( From 8ab44811a8f9b74c358c069d3bc0acc115e45235 Mon Sep 17 00:00:00 2001 From: designhorf Date: Tue, 1 Oct 2019 16:36:06 +0200 Subject: [PATCH 179/207] fix: long profile name in Toolbar --- src/renderer/wallet/main/toolbar.jsx | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/renderer/wallet/main/toolbar.jsx b/src/renderer/wallet/main/toolbar.jsx index 9085b62ff..5527633eb 100644 --- a/src/renderer/wallet/main/toolbar.jsx +++ b/src/renderer/wallet/main/toolbar.jsx @@ -68,7 +68,13 @@ const styles = theme => ({ flexDirection: 'column', justifyContent: 'space-around', margin: '0 20px 0 15px', - maxWidth: '118px' + maxWidth: '118px', + '& .toolbarProfileName': { + maxWidth: '110px', + overflow: 'hidden', + textOverflow: 'ellipsis', + whiteSpace: 'nowrap' + } }, sepVertContainer: { display: 'flex', @@ -295,7 +301,11 @@ const Profile = withStyles(styles)( )}
- + {profile.name || defaultIdentityName(profile, wallet.profileName)} From b5b648c18be5ebef22d8181f2ac2133054f66dcb Mon Sep 17 00:00:00 2001 From: Maxim Kovalov Date: Tue, 1 Oct 2019 19:20:08 +0300 Subject: [PATCH 180/207] fix(applications): applications with hw wallet --- src/common/kyc/index.js | 66 +++++++++++++------ src/main/blockchain/web3-service.js | 1 + src/main/kyc/kyc-application-service.js | 4 +- src/main/kyc/kyc-application.js | 6 +- ...20191001161321_kyc-application-identity.js | 26 ++++++++ .../containers/selfkey-id-applications.js | 42 +++++++++--- 6 files changed, 112 insertions(+), 33 deletions(-) create mode 100644 src/main/migrations/20191001161321_kyc-application-identity.js diff --git a/src/common/kyc/index.js b/src/common/kyc/index.js index 405045a30..b8106de24 100644 --- a/src/common/kyc/index.js +++ b/src/common/kyc/index.js @@ -1,5 +1,4 @@ import { marketplaceSelectors } from '../marketplace'; -import * as walletSelectors from '../wallet/selectors'; import { appSelectors } from '../app'; import { identitySelectors } from '../identity'; import { getGlobalContext } from '../context'; @@ -42,7 +41,8 @@ export const kycTypes = { KYC_APPLICATIONS_UPDATE: 'kyc/applications/update', KYC_APPLICATIONS_PROCESSING: 'kyc/applications/processing', KYC_APPLICATIONS_PROCESSING_SET: 'kyc/applications/set/processing', - KYC_APPLICATIONS_RESET: 'kyc/applications/reset' + KYC_APPLICATIONS_RESET: 'kyc/applications/reset', + KYC_APPLICATIONS_REFRESH: 'kyc/applications/refresh' }; const devRPDetails = { @@ -120,9 +120,9 @@ export const kycSelectors = { acc[curr.schemaId] = []; return acc; }, {}); - const wallet = walletSelectors.getWallet(state); + const identity = identitySelectors.selectCurrentIdentity(state); const walletAttributes = identitySelectors - .selectFullIdAttributesByIds(state, wallet.id) + .selectFullIdAttributesByIds(state, identity.id) .reduce((acc, curr) => { if (!curr || !curr.type || !curr.type.url) return acc; if (!acc.hasOwnProperty(curr.type.url)) return acc; @@ -158,9 +158,13 @@ export const kycSelectors = { }; }); }, - selectKYCAttributes(state, walletId, attributes = []) { + selectKYCAttributes(state, identityId, attributes = []) { const kycAttributes = identitySelectors - .selectFullIdAttributesByIds(state, walletId, attributes.map(attr => attr.attributeId)) + .selectFullIdAttributesByIds( + state, + identityId, + attributes.map(attr => attr.attributeId) + ) .reduce((acc, curr) => { acc[curr.id] = curr; return acc; @@ -322,8 +326,8 @@ const loadRelyingPartyOperation = ( const walletType = appSelectors.selectApp(state).walletType; if (!rpName) return null; - const wallet = walletSelectors.getWallet(state); - if (!wallet) return; + const identity = identitySelectors.selectCurrentIdentity(state); + if (!identity) return; const ts = Date.now(); @@ -358,7 +362,7 @@ const loadRelyingPartyOperation = ( await dispatch( kycOperations.updateApplicationsOperation({ id: application.id, - walletId: wallet.id, + identityId: identity.id, rpName: rpName, currentStatus: application.currentStatus, currentStatusName: application.statusName, @@ -416,14 +420,14 @@ const createRelyingPartyKYCApplication = (rpName, templateId, attributes, title) throw new Error('template does not exist'); } - const wallet = walletSelectors.getWallet(getState()); - if (!wallet) return; + const identity = identitySelectors.selectCurrentIdentity(getState()); + if (!identity) return; if (!rp.session.isActive()) { await rp.session.establish(); } - attributes = kycSelectors.selectKYCAttributes(getState(), wallet.id, attributes); + attributes = kycSelectors.selectKYCAttributes(getState(), identity.id, attributes); try { let application = await rp.session.createKYCApplication(templateId, attributes); application = await rp.session.getKYCApplication(application.id); @@ -432,7 +436,7 @@ const createRelyingPartyKYCApplication = (rpName, templateId, attributes, title) await dispatch( kycOperations.updateApplicationsOperation({ id: application.id, - walletId: wallet.id, + identityId: identity.id, rpName: rpName, currentStatus: application.currentStatus, currentStatusName: application.statusName, @@ -448,6 +452,26 @@ const createRelyingPartyKYCApplication = (rpName, templateId, attributes, title) } }; +const refreshRelyingPartyForKycApplication = (application, afterAuthRoute, cancelRoute) => async ( + dispatch, + getState +) => { + await dispatch( + kycOperations.loadRelyingParty(application.rpName, true, afterAuthRoute, cancelRoute) + ); + + const rp = kycSelectors.relyingPartySelector(getState(), application.rpName); + const kycApplication = rp.applications.find(app => app.id === application.id); + await dispatch( + kycOperations.updateApplicationsOperation({ + id: application.id, + currentStatus: kycApplication.currentStatus, + currentStatusName: kycApplication.statusName, + updatedAt: kycApplication.updatedAt + }) + ); +}; + const updateRelyingPartyKYCApplication = ( rpName, templateId, @@ -461,8 +485,8 @@ const updateRelyingPartyKYCApplication = ( throw new Error('template does not exist'); } - const wallet = walletSelectors.getWallet(getState()); - if (!wallet) return; + const identity = identitySelectors.selectCurrentIdentity(getState()); + if (!identity) return; if (!rp.session.isActive()) { await rp.session.establish(); @@ -471,7 +495,7 @@ const updateRelyingPartyKYCApplication = ( const updatedApplication = { id: applicationId, templateId }; if (attributes) { - attributes = kycSelectors.selectKYCAttributes(getState(), wallet.id, attributes); + attributes = kycSelectors.selectKYCAttributes(getState(), identity.id, attributes); updatedApplication.attributes = attributes; } if (questions) { @@ -486,7 +510,7 @@ const updateRelyingPartyKYCApplication = ( await dispatch( kycOperations.updateApplicationsOperation({ id: application.id, - walletId: wallet.id, + identityId: identity.id, rpName: rpName, currentStatus: application.currentStatus, currentStatusName: application.statusName, @@ -645,10 +669,10 @@ const clearRelyingPartyOperation = () => async dispatch => { }; const loadApplicationsOperation = () => async (dispatch, getState) => { - const wallet = walletSelectors.getWallet(getState()); + const identity = identitySelectors.selectCurrentIdentity(getState()); let kycApplicationService = getGlobalContext().kycApplicationService; await dispatch(kycActions.setProcessingAction(true)); - let applications = await kycApplicationService.load(wallet.id); + let applications = await kycApplicationService.load(identity.id); let sortedApplications = applications.sort((d1, d2) => { d1 = d1.createdAt ? new Date(d1.createdAt).getTime() : 0; d2 = d2.createdAt ? new Date(d2.createdAt).getTime() : 0; @@ -718,6 +742,10 @@ export const kycOperations = { resetApplications: createAliasedAction( kycTypes.KYC_APPLICATIONS_RESET, resetApplicationsOperation + ), + refreshRelyingPartyForKycApplication: createAliasedAction( + kycTypes.KYC_APPLICATIONS_REFRESH, + refreshRelyingPartyForKycApplication ) }; diff --git a/src/main/blockchain/web3-service.js b/src/main/blockchain/web3-service.js index 21938b98c..bffab80ee 100644 --- a/src/main/blockchain/web3-service.js +++ b/src/main/blockchain/web3-service.js @@ -98,6 +98,7 @@ export class Web3Service { } setDefaultAccount(account) { + this.defaultWallet(); this.web3.eth.accounts.wallet.add(account); this.setDefaultAddress(account.address); } diff --git a/src/main/kyc/kyc-application-service.js b/src/main/kyc/kyc-application-service.js index 59117c369..2c9c23b59 100644 --- a/src/main/kyc/kyc-application-service.js +++ b/src/main/kyc/kyc-application-service.js @@ -31,8 +31,8 @@ export class KycApplicationService { return KycApplication.findById(id); }; - load = walletId => { - return KycApplication.findAll(walletId); + load = identityId => { + return KycApplication.findAll(identityId); }; } diff --git a/src/main/kyc/kyc-application.js b/src/main/kyc/kyc-application.js index 62bf36ffb..92b1ebe40 100644 --- a/src/main/kyc/kyc-application.js +++ b/src/main/kyc/kyc-application.js @@ -27,7 +27,7 @@ export class KycApplication extends BaseModel { applicationDate: { type: 'string' }, payments: { type: 'object' }, nextRoute: { type: 'string' }, - walletId: { type: 'integer' } + identityId: { type: 'integer' } } }; } @@ -36,8 +36,8 @@ export class KycApplication extends BaseModel { return this.query().findById(id); } - static findAll(walletId) { - return this.query().where({ walletId }); + static findAll(identityId) { + return this.query().where({ identityId }); } static async create(itm) { diff --git a/src/main/migrations/20191001161321_kyc-application-identity.js b/src/main/migrations/20191001161321_kyc-application-identity.js new file mode 100644 index 000000000..d5708bb24 --- /dev/null +++ b/src/main/migrations/20191001161321_kyc-application-identity.js @@ -0,0 +1,26 @@ +/* istanbul ignore file */ +exports.up = async (knex, Promise) => { + await knex.schema.alterTable('kyc_applications', t => { + t.string('identityId').references('identity.id'); + }); + const applications = await knex('kyc_applications').select(); + const identities = await knex('identities') + .select() + .where({ type: 'individual' }); + if (!applications.length || !identities.length) return; + const mapIdentities = identities.reduce((acc, curr) => { + acc[curr.walletId] = curr; + return acc; + }, {}); + await Promise.all( + applications.map(async application => { + await knex('kyc_applications') + .update({ + identityId: mapIdentities[application.walletId].id + }) + .where({ walletId: application.walletId }); + }) + ); +}; + +exports.down = async (knex, Promise) => {}; diff --git a/src/renderer/selfkey-id/main/containers/selfkey-id-applications.js b/src/renderer/selfkey-id/main/containers/selfkey-id-applications.js index 79634e5b5..c191c3055 100644 --- a/src/renderer/selfkey-id/main/containers/selfkey-id-applications.js +++ b/src/renderer/selfkey-id/main/containers/selfkey-id-applications.js @@ -9,7 +9,8 @@ import { kycSelectors } from '../../../../common/kyc'; class SelfkeyIdApplicationsContainerComponent extends Component { state = { - showApplicationRefreshModal: false + showApplicationRefreshModal: false, + loading: true }; async componentDidMount() { @@ -20,12 +21,20 @@ class SelfkeyIdApplicationsContainerComponent extends Component { await this.props.dispatch(marketplaceOperations.loadMarketplaceOperation()); // load existing kyc_applications data await this.props.dispatch(kycOperations.loadApplicationsOperation()); + if (this.props.wallet.profile === 'local') { + await this.loadRelyingParties(vendors); + } - await this.loadRelyingParties(vendors); + setTimeout(() => { + this.setState({ loading: false }); + }, 2000); } async componentDidUpdate(prevProps) { - if (prevProps.vendors.length !== this.props.vendors.length) { + if ( + prevProps.vendors.length !== this.props.vendors.length && + this.props.wallet.profile === 'local' + ) { await this.loadRelyingParties(this.props.vendors); } } @@ -52,7 +61,7 @@ class SelfkeyIdApplicationsContainerComponent extends Component { // get current application info from RP const rp = rps[application.rpName]; if (!rp) { - console.warning(`Can't find RP named ${application.rpName}`); + console.error(`Can't find RP named ${application.rpName}`); return false; } // Later on, we will need to improve this to be able to distinguish requirements @@ -67,15 +76,25 @@ class SelfkeyIdApplicationsContainerComponent extends Component { }; handleApplicationRefresh = application => { - const { rps } = this.props; + const { rps, wallet, dispatch, afterAuthRoute, cancelRoute } = this.props; // get current application info from RP const rp = rps[application.rpName]; - if (!rp) { + if (!rp && wallet.profile === 'local') { console.warning(`Can't find RP named ${application.rpName}`); return false; } + if (wallet.profile !== 'local') { + return dispatch( + kycOperations.refreshRelyingPartyForKycApplication( + application, + afterAuthRoute, + cancelRoute + ) + ); + } + const kycApplication = rp.applications.find(app => app.id === application.id); if (application && kycApplication) { @@ -97,8 +116,12 @@ class SelfkeyIdApplicationsContainerComponent extends Component { }; render() { - const { rps, vendors } = this.props; - const loading = Object.keys(rps).length === 0 || vendors.length === 0; + const { rps, vendors, wallet } = this.props; + let loading = this.state.loading; + if (wallet.profile === 'local') { + loading = Object.keys(rps).length === 0 || vendors.length === 0; + } + return ( { applications: kycSelectors.selectApplications(state), afterAuthRoute: walletType === 'ledger' || walletType === 'trezor' ? `/main/selfkeyIdApplications` : '', - cancelRoute: `/main/selfkeyId` + cancelRoute: `/main/selfkeyId`, + walletType }; }; From 7d3af42ff77cfb07ae80fe7156b035f2c4852ebe Mon Sep 17 00:00:00 2001 From: Maxim Kovalov Date: Wed, 2 Oct 2019 11:28:49 +0300 Subject: [PATCH 181/207] fix: tests --- src/common/kyc/kyc-duck.spec.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/common/kyc/kyc-duck.spec.js b/src/common/kyc/kyc-duck.spec.js index b64c74cc4..a1b5709cc 100644 --- a/src/common/kyc/kyc-duck.spec.js +++ b/src/common/kyc/kyc-duck.spec.js @@ -1,5 +1,6 @@ import sinon from 'sinon'; import { setGlobalContext } from '../context'; +import { identitySelectors } from '../identity'; import { kycActions, kycTypes, reducers, initialState, kycSelectors, testExports } from './index'; describe('KYC Duck', () => { @@ -28,6 +29,7 @@ describe('KYC Duck', () => { describe('Operations', () => { it('loadApplicationsOperation', async () => { sinon.stub(kycApplicationService, 'load').resolves(testApplications); + sinon.stub(identitySelectors, 'selectCurrentIdentity').returns({ id: 1 }); sinon.stub(store, 'dispatch'); await testExports.operations.loadApplicationsOperation()( From fda1bb1377efaf579b1b93c0bd43516ddc08a9bf Mon Sep 17 00:00:00 2001 From: designhorf Date: Wed, 2 Oct 2019 10:38:22 +0200 Subject: [PATCH 182/207] fix: cahanged the text Vault to Wallet --- src/renderer/corporate/wizard/corporate-wizard.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/corporate/wizard/corporate-wizard.jsx b/src/renderer/corporate/wizard/corporate-wizard.jsx index a2ff2bd84..b07d34340 100644 --- a/src/renderer/corporate/wizard/corporate-wizard.jsx +++ b/src/renderer/corporate/wizard/corporate-wizard.jsx @@ -574,7 +574,7 @@ class CorporateWizardComponent extends Component { return ( - SelfKey Corporate Vault Setup + SelfKey Corporate Wallet Setup From bf9d607c4deedf0cd047ee213cafa45841172aeb Mon Sep 17 00:00:00 2001 From: designhorf Date: Wed, 2 Oct 2019 10:43:24 +0200 Subject: [PATCH 183/207] fix: aligned left Continue button --- src/renderer/corporate/wizard/corporate-wizard.jsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/renderer/corporate/wizard/corporate-wizard.jsx b/src/renderer/corporate/wizard/corporate-wizard.jsx index b07d34340..e4be78599 100644 --- a/src/renderer/corporate/wizard/corporate-wizard.jsx +++ b/src/renderer/corporate/wizard/corporate-wizard.jsx @@ -55,8 +55,7 @@ const styles = theme => ({ paddingLeft: '20px' }, footer: { - paddingTop: '20px', - paddingLeft: '16px' + paddingTop: '20px' }, divider: { backgroundColor: '#475768', From 146e50b7a30aa33a14270b78830eb9a773bfb28e Mon Sep 17 00:00:00 2001 From: Andre Goncalves Date: Wed, 2 Oct 2019 11:07:38 +0100 Subject: [PATCH 184/207] feat: certifiers feature flag --- src/common/config.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/common/config.js b/src/common/config.js index c6b6b87e8..f4eda7d6f 100644 --- a/src/common/config.js +++ b/src/common/config.js @@ -121,7 +121,8 @@ const common = { features: { paymentContract: false, scheduler: true, - corporate: false + corporate: false, + certifiers: false } }; @@ -142,7 +143,8 @@ const dev = { features: { paymentContract: false, scheduler: true, - corporate: true + corporate: true, + certifiers: true }, testWalletAddress: '0x23d233933c86f93b74705cf0d236b39f474249f8', testDidAddress: '0xee10a3335f48e10b444e299cf017d57879109c1e32cec3e31103ceca7718d0ec', From 1f9f0b24b9f60c746c8683e7cf1eeaa9b43da0fc Mon Sep 17 00:00:00 2001 From: designhorf Date: Wed, 2 Oct 2019 13:33:49 +0200 Subject: [PATCH 185/207] fix: removed grids and modified paddings/margins --- .../corporate/wizard/corporate-wizard.jsx | 600 ++++++------------ 1 file changed, 188 insertions(+), 412 deletions(-) diff --git a/src/renderer/corporate/wizard/corporate-wizard.jsx b/src/renderer/corporate/wizard/corporate-wizard.jsx index e4be78599..c66acab2c 100644 --- a/src/renderer/corporate/wizard/corporate-wizard.jsx +++ b/src/renderer/corporate/wizard/corporate-wizard.jsx @@ -1,16 +1,8 @@ import React, { Component } from 'react'; - import { - Grid, CardHeader, Card, CardContent, - // Table, - // TableBody, - // TableRow, - // TableCell, - // IconButton, - // TableHead, Typography, Button, Input, @@ -19,7 +11,7 @@ import { withStyles } from '@material-ui/core'; import { KeyboardArrowDown } from '@material-ui/icons'; -import { /* EditTransparentIcon, DeleteIcon, SmallTableHeadRow, */ KeyPicker } from 'selfkey-ui'; +import { KeyPicker } from 'selfkey-ui'; const styles = theme => ({ hr: { @@ -27,26 +19,13 @@ const styles = theme => ({ border: 'none', boxSizing: 'border-box', height: '1px', - margin: '5px 16px' + margin: '5px 30px 10px' }, card: { overflow: 'visible' }, - labelCell: { - whiteSpace: 'normal', - wordBreak: 'break-all', - '& > div': { - alignItems: 'center' - } - }, - cardHeader: { - whiteSpace: 'normal', - wordBreak: 'break-all' - }, - button: { - marginBottom: '16px' - }, regularText: { + padding: '24px 30px', '& span': { fontWeight: 400 } @@ -55,26 +34,19 @@ const styles = theme => ({ paddingLeft: '20px' }, footer: { - paddingTop: '20px' - }, - divider: { - backgroundColor: '#475768', - width: '100%', - marginTop: '10px', - marginBottom: '10px' - }, - dropdown: { - width: '322px' - }, - idNickname: { - alignItems: 'baseline', + alignItems: 'flex-start', display: 'flex', - flexDirection: 'row' + justifyContent: 'flex-start', + paddingTop: '60px' }, inputBox: { marginBottom: '35px', width: '47%' }, + lastInputBox: { + marginBottom: '26px', + width: '47%' + }, keyBox: { marginBottom: '35px', marginRight: 'calc(47% - 200px)', @@ -88,9 +60,49 @@ const styles = theme => ({ fontStyle: 'italic', marginLeft: '5px', textTransform: 'lowercase' + }, + select: { + width: '100%' + }, + flexColumn: { + display: 'flex', + flexDirection: 'column' + }, + inputContainer: { + alignItems: 'flex-start', + justify: 'flex-start' + }, + inputWrap: { + display: 'flex', + flexWrap: 'nowrap', + justifyContent: 'space-between', + width: '100%' + }, + cardContent: { + padding: '24px 30px' + }, + wizardTitle: { + marginBottom: '45px' } }); +const InputTitle = withStyles(styles)(({ classes, title, optional = false }) => { + return ( +
+ + {title} + {optional ? ( + + (optional) + + ) : ( + '' + )} + +
+ ); +}); + const CompanyInformation = withStyles(styles)(props => { const { classes, @@ -106,341 +118,121 @@ const CompanyInformation = withStyles(styles)(props => { onFieldChange = () => {} } = props; return ( - - - - -
- - - - -
- - - - - - - - - - Legal Jurisdiction - - - - - - - - - - Legal Entity Name - - - - - - - - - - - - Legal Entity Type - - - - - - - - - - Creation Date - - - - div': { - width: - '200px !important' - } - }} - /> - - - - - - - - Contact Email - - (optional) - - - - - - {errors.email && ( - - { - 'Email provided is invalid' - } - - )} - - - - - - Tax ID - - (optional) - - - - - - - - - - - - - -
-
-
-
-
-
-
-
+
+ + +
+ +
+
+
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + div': { + width: '200px !important' + } + }} + /> +
+
+
+
+ + + {errors.email && ( + + {'Email provided is invalid'} + + )} +
+
+ + +
+
+
+
+
+
+
); }); @@ -571,47 +363,31 @@ class CorporateWizardComponent extends Component { render() { const { classes } = this.props; return ( - - +
+
SelfKey Corporate Wallet Setup - - - - - - - {/* */} - - - +
+ + {/* */} +
+
+
+ - - - - - - - - + Continue + +
+
+ +
+
+
); } } From 38aaf989261930c11dd6d7cce3ecc6a1704a8d80 Mon Sep 17 00:00:00 2001 From: designhorf Date: Wed, 2 Oct 2019 13:48:29 +0200 Subject: [PATCH 186/207] fix: changed text Vault to Wallet in corp dashboard --- src/renderer/corporate/dashboard/dashboard-page.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/corporate/dashboard/dashboard-page.jsx b/src/renderer/corporate/dashboard/dashboard-page.jsx index 5d24d2c02..881fdd5a3 100644 --- a/src/renderer/corporate/dashboard/dashboard-page.jsx +++ b/src/renderer/corporate/dashboard/dashboard-page.jsx @@ -37,7 +37,7 @@ class CorporateDashboardPage extends CorporateComponent { > - SelfKey Corporate Vault + SelfKey Corporate Wallet From 30a7c03fd4444212b48dd7e0b93c42ece0903192 Mon Sep 17 00:00:00 2001 From: Maxim Kovalov Date: Thu, 3 Oct 2019 11:29:20 +0300 Subject: [PATCH 187/207] fix(profile): create individual profile if needed --- src/common/identity/operations.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/common/identity/operations.js b/src/common/identity/operations.js index f8c483cb8..ef4adf229 100644 --- a/src/common/identity/operations.js +++ b/src/common/identity/operations.js @@ -295,6 +295,10 @@ const switchProfileOperation = identity => async (dispatch, getState) => { const navigateToProfileOperation = () => async (dispatch, getState) => { const identity = identitySelectors.selectCurrentIdentity(getState()); + if (identity.type === 'individual' && !identity.isSetupFinished) { + return dispatch(push('/selfkeyIdCreate')); + } + if (identity.type === 'individual') { return dispatch(push('/main/selfkeyId')); } From 4fb9e1e67e9b8d23fa3a17cfd89bca9ac4245e59 Mon Sep 17 00:00:00 2001 From: Andre Goncalves Date: Thu, 3 Oct 2019 09:33:54 +0100 Subject: [PATCH 188/207] fix: errors while displaying array info --- .../vendors/vendor-sync-job-handler.js | 1 - .../marketplace/services/service-details.jsx | 59 +++++++++++-------- .../services/services-list-item.jsx | 17 ++++-- 3 files changed, 47 insertions(+), 30 deletions(-) diff --git a/src/main/marketplace/vendors/vendor-sync-job-handler.js b/src/main/marketplace/vendors/vendor-sync-job-handler.js index a13dd2c26..84c14be37 100644 --- a/src/main/marketplace/vendors/vendor-sync-job-handler.js +++ b/src/main/marketplace/vendors/vendor-sync-job-handler.js @@ -22,7 +22,6 @@ export class VendorSyncJobHandler { job.emitProgress(25, { message: 'load db vendors' }); const dbVendors = await this.vendorService.loadVendors(); - job.emitProgress(50, { message: 'load db vendors' }); job.emitProgress(50, { message: 'Merging remote and local data' }); diff --git a/src/renderer/marketplace/services/service-details.jsx b/src/renderer/marketplace/services/service-details.jsx index 641aec344..0414d0fa4 100644 --- a/src/renderer/marketplace/services/service-details.jsx +++ b/src/renderer/marketplace/services/service-details.jsx @@ -421,18 +421,19 @@ class MarketplaceServiceDetailsComponent extends Component { const getColors = () => ['#46dfba', '#46b7df', '#238db4', '#25a788', '#0e4b61']; let random = Math.floor(Math.random() * 4); - const icon = item.data.logo[0].url ? ( - - ) : ( -
- {item.name.charAt(0)} -
- ); + const icon = + item.data.logo && item.data.logo[0].url ? ( + + ) : ( +
+ {item.name.charAt(0)} +
+ ); return ( @@ -536,9 +537,10 @@ class MarketplaceServiceDetailsComponent extends Component { Location: - {item.data.location.map(name => ( - {`${name} `} - ))} + {item.data.location && + item.data.location.map(name => ( + {`${name} `} + ))} @@ -584,9 +586,10 @@ class MarketplaceServiceDetailsComponent extends Component { FIAT Payment: - {item.data.fiatPayments.map(name => ( - {`${name} `} - ))} + {item.data.fiatPayments && + item.data.fiatPayments.map(name => ( + {`${name} `} + ))} @@ -594,9 +597,10 @@ class MarketplaceServiceDetailsComponent extends Component { FIAT Supported: - {item.data.fiatSupported.map(name => ( - {`${name} `} - ))} + {item.data.fiatSupported && + item.data.fiatSupported.map(name => ( + {`${name} `} + ))} @@ -618,9 +622,14 @@ class MarketplaceServiceDetailsComponent extends Component { Excluded Resident: - {item.data.excludedResidents.map(name => ( - {`${name} `} - ))} + {item.data.excludedResidents && + item.data.excludedResidents.map( + name => ( + {`${name} `} + ) + )} @@ -634,7 +643,7 @@ class MarketplaceServiceDetailsComponent extends Component {
- {templates[0] && ( + {templates && templates[0] && ( From 4fa6c18cddd7df5f9a8343dc33ae8329e38a9188 Mon Sep 17 00:00:00 2001 From: Maxim Kovalov Date: Thu, 3 Oct 2019 11:44:56 +0300 Subject: [PATCH 189/207] fix(corporate-profile): navigate to profile flickers --- src/renderer/wallet/main/sidebar.jsx | 5 ++--- src/renderer/wallet/main/toolbar.jsx | 6 +++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/renderer/wallet/main/sidebar.jsx b/src/renderer/wallet/main/sidebar.jsx index b9c66e88f..28417a61b 100644 --- a/src/renderer/wallet/main/sidebar.jsx +++ b/src/renderer/wallet/main/sidebar.jsx @@ -185,7 +185,6 @@ const styles = theme => ({ const dashboard = props => ; const marketplace = props => ; -const selfkeyId = props => ; const addressBook = props => ; const switchAccount = props => ; @@ -212,7 +211,7 @@ class Sidebar extends Component { }; render() { - const { classes } = this.props; + const { classes, onProfileNavigate } = this.props; const sideList = ( diff --git a/src/renderer/wallet/main/toolbar.jsx b/src/renderer/wallet/main/toolbar.jsx index 5527633eb..1c8bdd698 100644 --- a/src/renderer/wallet/main/toolbar.jsx +++ b/src/renderer/wallet/main/toolbar.jsx @@ -345,7 +345,11 @@ class Toolbar extends Component { } = this.props; return (
- + Date: Thu, 3 Oct 2019 10:46:02 +0200 Subject: [PATCH 190/207] fix: application status table --- .../common/corporate-applications.jsx | 68 +++++++++++-------- 1 file changed, 38 insertions(+), 30 deletions(-) diff --git a/src/renderer/corporate/common/corporate-applications.jsx b/src/renderer/corporate/common/corporate-applications.jsx index aad8918c0..baa84af81 100644 --- a/src/renderer/corporate/common/corporate-applications.jsx +++ b/src/renderer/corporate/common/corporate-applications.jsx @@ -1,6 +1,5 @@ import React from 'react'; import { - Grid, CardHeader, Card, CardContent, @@ -8,11 +7,16 @@ import { Table, TableHead, TableBody, - TableRow, - TableCell, withStyles } from '@material-ui/core'; -import { HourGlassSmallIcon, CheckMaIcon, DeniedIcon, SmallTableHeadRow } from 'selfkey-ui'; +import { + HourGlassSmallIcon, + CheckMaIcon, + DeniedIcon, + SmallTableRow, + SmallTableCell, + SmallTableHeadRow +} from 'selfkey-ui'; const styles = theme => ({ container: { @@ -25,11 +29,17 @@ const styles = theme => ({ height: '1px', margin: '5px 16px' }, - card: {}, cardHeader: { whiteSpace: 'normal', wordBreak: 'break-all' }, + cardContent: { + alignItems: 'flex-start', + display: 'flex', + flexDirection: 'column', + maxHeight: '180px', + overflow: 'scroll' + }, regularText: { '& span': { fontWeight: 400 @@ -64,46 +74,44 @@ const CorporateApplicationsSummary = withStyles(styles)(props => { const { classes, applications = [] } = props; return ( - +
- - + +
- + Service - - + + Provider - - + + Status - + {applications && applications.map(a => ( - - - {a.title} - - - {a.rpName} - - {renderStatus(a.currentStatusName)} - + + + {a.title} + + + {a.rpName} + + + + {renderStatus(a.currentStatusName)} + + + ))}
- +
); From 3dd14b0bc48ae10a6960da5ba1835e4dda8cd251 Mon Sep 17 00:00:00 2001 From: designhorf Date: Thu, 3 Oct 2019 10:50:53 +0200 Subject: [PATCH 191/207] fix: cap table --- .../corporate/common/corporate-cap-table.jsx | 105 +++++++++--------- 1 file changed, 51 insertions(+), 54 deletions(-) diff --git a/src/renderer/corporate/common/corporate-cap-table.jsx b/src/renderer/corporate/common/corporate-cap-table.jsx index 265d6baa5..2396a9d40 100644 --- a/src/renderer/corporate/common/corporate-cap-table.jsx +++ b/src/renderer/corporate/common/corporate-cap-table.jsx @@ -1,6 +1,5 @@ import React from 'react'; import { - Grid, CardHeader, Card, CardContent, @@ -8,11 +7,9 @@ import { Table, TableHead, TableBody, - TableRow, - TableCell, withStyles } from '@material-ui/core'; -import { EditTransparentIcon, SmallTableHeadRow } from 'selfkey-ui'; +import { SmallTableRow, SmallTableCell, EditTransparentIcon, SmallTableHeadRow } from 'selfkey-ui'; const styles = theme => ({ hr: { @@ -22,12 +19,14 @@ const styles = theme => ({ height: '1px', margin: '5px 16px' }, - card: { + cardHeader: { height: '100%' }, - cardHeader: { - whiteSpace: 'normal', - wordBreak: 'break-all' + cardContent: { + alignItems: 'flex-item', + display: 'flex', + flexDirection: 'column', + justifyContent: 'center' }, cardAction: { padding: '1em 1em 0' @@ -55,78 +54,76 @@ const CorporateCapTable = withStyles(styles)(props => { root: classes.regularText, action: classes.cardAction }} - className={classes.card} + className={classes.cardHeader} action={editAction(onEdit)} />
- +
- + Type - - + + Role - - + + Name - - + + Email - - + + Citizenship / Incorporation - - + + Residency / Domicile - - + + Shares - + {cap && cap.map((c, idx) => ( - - - {c.type} - - - {c.role} - - - {c.name} - - - + + + {c.type} + + + {c.role} + + + {c.name} + + + {c.email ? c.email : '-'} - - - {c.citizenship} - - - {c.residency} - - - {c.shares} - - + + + + {c.citizenship} + + + + + {c.residency} + + + + {c.shares} + + ))}
- +
); From 1990c997abf9bdeb0c99d192f5f5c9b8763c2d33 Mon Sep 17 00:00:00 2001 From: designhorf Date: Thu, 3 Oct 2019 11:00:08 +0200 Subject: [PATCH 192/207] fix: alignment and removed unnecessary Grids --- .../corporate/common/corporate-details.jsx | 28 ++- .../corporate/common/corporate-documents.jsx | 186 ++++++++---------- .../corporate/common/corporate-org-chart.jsx | 4 +- .../common/corporate-shareholding.jsx | 92 ++++----- .../corporate/dashboard/dashboard-tabs.jsx | 68 +++---- .../corporate/dashboard/overview-tab.jsx | 95 +++++---- src/renderer/did/register-did-card.jsx | 2 +- 7 files changed, 216 insertions(+), 259 deletions(-) diff --git a/src/renderer/corporate/common/corporate-details.jsx b/src/renderer/corporate/common/corporate-details.jsx index 8e4729944..056ddf1ca 100644 --- a/src/renderer/corporate/common/corporate-details.jsx +++ b/src/renderer/corporate/common/corporate-details.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Grid, CardHeader, Card, CardContent, Typography, withStyles } from '@material-ui/core'; +import { CardHeader, Card, CardContent, Typography, withStyles } from '@material-ui/core'; import { CheckMaIcon, AttributeAlertIcon, EditTransparentIcon } from 'selfkey-ui'; const styles = theme => ({ @@ -10,10 +10,14 @@ const styles = theme => ({ height: '1px', margin: '5px 16px' }, - card: {}, - cardHeader: { - whiteSpace: 'normal', - wordBreak: 'break-all' + cardContentBox: { + height: 'initial' + }, + cardContent: { + alignItems: 'flex-start', + display: 'flex', + flexDirection: 'column', + justifyContent: 'center' }, cardAction: { padding: '1em 1em 0' @@ -24,8 +28,8 @@ const styles = theme => ({ } }, attr: { - margin: '0.5em', display: 'block', + marginBottom: '20px', '& .label': { display: 'inline-block', minWidth: '12em' @@ -80,14 +84,8 @@ const CorporateDetails = withStyles(styles)(props => { action={editAction(onEdit)} />
- - + +
Jurisdiction @@ -120,7 +118,7 @@ const CorporateDetails = withStyles(styles)(props => { {profile.did}
)} - +
); diff --git a/src/renderer/corporate/common/corporate-documents.jsx b/src/renderer/corporate/common/corporate-documents.jsx index 56bdd2d5f..4e8809a80 100644 --- a/src/renderer/corporate/common/corporate-documents.jsx +++ b/src/renderer/corporate/common/corporate-documents.jsx @@ -1,7 +1,6 @@ import React from 'react'; import moment from 'moment'; import { - Grid, CardHeader, Card, CardContent, @@ -34,37 +33,35 @@ const styles = theme => ({ height: '1px', margin: '5px 16px' }, - card: {}, + card: { + marginTop: '22px' + }, cardHeader: { whiteSpace: 'normal', wordBreak: 'break-all' }, + cardContent: { + alignItems: 'center', + display: 'flex', + flexDirection: 'column', + justifyContent: 'center' + }, regularText: { '& span': { fontWeight: 400 } }, - attr: { - margin: '0.5em', - display: 'block', - '& .label': { - display: 'inline-block', - minWidth: '12em' - }, - '& h5': { - display: 'inline-block' - }, - '& svg': { - marginRight: '0.5em', - verticalAlign: 'middle' - } - }, documentColumn: { display: 'flex', alignItems: 'center', '& .file-icon': { marginRight: '15px' } + }, + button: { + display: 'flex', + justifyContent: 'center', + marginTop: '30px' } }); @@ -127,93 +124,78 @@ const DocumentExpiryDate = ({ doc }) => { const CorporateDocuments = withStyles(styles)(props => { const { classes, documents = [], onEditDocument, onDeleteDocument, onAddDocument } = props; return ( - +
- - - - - - - - - Type - - - Label - - - Expiry Date - - - Last Edited - - - Actions - - - - - {documents.map(entry => ( - - - - {renderAttributeTitle(entry)} - - - - {renderDocumentName({ entry, classes })} - - - - - - - {renderLastUpdateDate(entry)} - - - - onEditDocument(entry)} - > - - - onDeleteDocument(entry)} - > - - - - - ))} - -
-
-
- - - - - -
+ + + + + + Type + + + Label + + + Expiry Date + + + Last Edited + + + Actions + + + + + {documents.map(entry => ( + + + + {renderAttributeTitle(entry)} + + + + {renderDocumentName({ entry, classes })} + + + + + + + {renderLastUpdateDate(entry)} + + + + onEditDocument(entry)} + > + + + onDeleteDocument(entry)} + > + + + + + ))} + +
+
+ +
); diff --git a/src/renderer/corporate/common/corporate-org-chart.jsx b/src/renderer/corporate/common/corporate-org-chart.jsx index e0030dfe4..8761a8b9c 100644 --- a/src/renderer/corporate/common/corporate-org-chart.jsx +++ b/src/renderer/corporate/common/corporate-org-chart.jsx @@ -1,12 +1,12 @@ import React from 'react'; import { Grid, CardHeader, Card, CardContent, withStyles } from '@material-ui/core'; -import { base, grey, EditTransparentIcon } from 'selfkey-ui'; +import { grey, EditTransparentIcon } from 'selfkey-ui'; import 'react-orgchart/index.css'; import OrgChart from 'react-orgchart'; const styles = theme => ({ hr: { - backgroundColor: `${base}`, + backgroundColor: '#303C49', border: 'none', boxSizing: 'border-box', height: '1px', diff --git a/src/renderer/corporate/common/corporate-shareholding.jsx b/src/renderer/corporate/common/corporate-shareholding.jsx index b856196cb..79c32fe6d 100644 --- a/src/renderer/corporate/common/corporate-shareholding.jsx +++ b/src/renderer/corporate/common/corporate-shareholding.jsx @@ -3,9 +3,6 @@ import { Grid, CardHeader, Card, CardContent, withStyles } from '@material-ui/co import { Chart } from 'react-google-charts'; const styles = theme => ({ - cardContainer: { - maxWidth: '550px' - }, hr: { backgroundColor: '#303C49', border: 'none', @@ -13,30 +10,19 @@ const styles = theme => ({ height: '1px', margin: '5px 16px' }, - card: {}, - cardHeader: { - whiteSpace: 'normal', - wordBreak: 'break-all' + cardContent: { + height: 'initial' }, regularText: { + boxSizing: 'border-box', + height: 58, '& span': { fontWeight: 400 } }, - attr: { - margin: '0.5em', - display: 'block', - '& .label': { - display: 'inline-block', - minWidth: '12em' - }, - '& h5': { - display: 'inline-block' - }, - '& svg': { - marginRight: '0.5em', - verticalAlign: 'middle' - } + chartWrap: { + alignItems: 'flex-start', + display: 'flex' }, legend: { alignSelf: 'flex-end', @@ -113,41 +99,37 @@ ref={c => { const CorporateShareholding = withStyles(styles)(props => { const { classes, cap = [] } = props; return ( - - - - -
- - - - + +
+ +
+ + + + + {cap.map((shareholder, index) => ( +
+
- - - {cap.map((shareholder, index) => ( -
-
- {shareholder.name} -
- ))} - - - - - - + {shareholder.name} +
+ ))} +
+
+ + ); }); diff --git a/src/renderer/corporate/dashboard/dashboard-tabs.jsx b/src/renderer/corporate/dashboard/dashboard-tabs.jsx index 38bb50c53..cdf060000 100644 --- a/src/renderer/corporate/dashboard/dashboard-tabs.jsx +++ b/src/renderer/corporate/dashboard/dashboard-tabs.jsx @@ -1,48 +1,48 @@ import React from 'react'; -import { withStyles, Tabs, Tab, Grid } from '@material-ui/core'; +import { withStyles, Tabs, Tab } from '@material-ui/core'; import { CorporateOverviewTab } from './overview-tab'; import { CorporateInformationTab } from './information-tab'; import { CorporateMembersTab } from './members-tab'; import { CorporateApplicationsTab } from './applications-tab'; import { CorporateHistoryTab } from './history-tab'; -const styles = theme => ({}); +const styles = theme => ({ + dashboardTabs: { + alignItems: 'stretch', + display: 'flex', + flexDirection: 'column', + justifyContent: 'flex-start' + }, + tabs: { + marginBottom: '40px' + } +}); export const CorporateDashboardTabs = withStyles(styles)( ({ classes, tab = 'overview', onTabChange, ...tabProps }) => { return ( - - - onTabChange(value)}> - - - - - - - - - {tab === 'overview' && } - {tab === 'information' && ( - - )} - {tab === 'members' && } - {tab === 'applications' && ( - - )} - {tab === 'history' && } - - +
+ onTabChange(value)} + > + + + + + + + {tab === 'overview' && } + {tab === 'information' && ( + + )} + {tab === 'members' && } + {tab === 'applications' && ( + + )} + {tab === 'history' && } +
); } ); diff --git a/src/renderer/corporate/dashboard/overview-tab.jsx b/src/renderer/corporate/dashboard/overview-tab.jsx index ba3819f86..295bcc3be 100644 --- a/src/renderer/corporate/dashboard/overview-tab.jsx +++ b/src/renderer/corporate/dashboard/overview-tab.jsx @@ -7,63 +7,58 @@ import { CorporateShareholding } from '../common/corporate-shareholding'; import { CorporateOrgChart } from '../common/corporate-org-chart'; const styles = theme => ({ - corporateShareholding: { - width: '550px' + overviewBox: { + alignItems: 'strech', + display: 'flex', + flexDirection: 'column', + justifyContent: 'flex-start', + '& .halfWidgetBox': { + alignItems: 'stretch', + display: 'flex', + flexWrap: 'nowrap', + justifyContent: 'space-between', + margin: '30px 0', + '& .halfWidth': { + width: '100%' + }, + '& .halfWidth:first-child': { + marginRight: 15 + }, + '& .halfWidth:last-child': { + marginLeft: 15 + } + } } }); const CorporateOverviewTab = withStyles(styles)( ({ classes, applications, profile, cap, onEditCorporateDetails, didComponent }) => ( -
- +
+
{!profile.did && {didComponent}} - - - - - - - - - - - +
+
+ +
+
+ +
+
+
- - - - - - - - - - - - +
+
+
+ +
+
+ +
+
+
) ); diff --git a/src/renderer/did/register-did-card.jsx b/src/renderer/did/register-did-card.jsx index 26b977c09..5a0df0bad 100644 --- a/src/renderer/did/register-did-card.jsx +++ b/src/renderer/did/register-did-card.jsx @@ -76,7 +76,7 @@ class RegisterDidCardComponent extends Component {
- + Use a DID when accesing different services in the marketplace. Once created you’ll see it under your profile. From f9a1a5a7cf04abf0016226e0cc7a1e2b4d666c24 Mon Sep 17 00:00:00 2001 From: designhorf Date: Thu, 3 Oct 2019 11:03:02 +0200 Subject: [PATCH 193/207] fix: changed icon in information and removed grids --- .../common/corporate-information.jsx | 197 +++++++++--------- 1 file changed, 95 insertions(+), 102 deletions(-) diff --git a/src/renderer/corporate/common/corporate-information.jsx b/src/renderer/corporate/common/corporate-information.jsx index 04e5bd23e..3e3463982 100644 --- a/src/renderer/corporate/common/corporate-information.jsx +++ b/src/renderer/corporate/common/corporate-information.jsx @@ -14,7 +14,7 @@ import { withStyles } from '@material-ui/core'; import { - IdCardIcon, + BookIcon, SmallTableHeadRow, SmallTableRow, SmallTableCell, @@ -35,6 +35,12 @@ const styles = theme => ({ whiteSpace: 'normal', wordBreak: 'break-all' }, + cardContent: { + alignItems: 'stretch', + display: 'flex', + flexDirection: 'column', + justifyContent: 'center' + }, cardAction: { padding: '20px' }, @@ -57,6 +63,22 @@ const styles = theme => ({ marginRight: '0.5em', verticalAlign: 'middle' } + }, + informationLeft: { + alignItems: 'center', + display: 'flex', + flexDirection: 'column', + flexWrap: 'nowrap', + justifyContent: 'flex-end', + paddingRight: '30px' + }, + bookIcon: { + margin: '30px 0 20px' + }, + button: { + display: 'flex', + justifyContent: 'center', + marginTop: '30px' } }); @@ -86,115 +108,86 @@ const CorporateInformation = withStyles(styles)(props => {
- - - - - - - - - - - - Information provided here will be used for the KYC - processes in the Marketplace. - - - - - - - - - - - Information + +
+ + +
+ + + Information provided here will be used for the KYC processes in + the Marketplace. + +
+
+ +
+ + + + Information + + + Label + + + Last edited + + + Actions + + + + + {attributes.map(attr => ( + + + + {renderAttributeTitle(attr)} - - Label + + + {renderAttributeValue(attr)} + - - - Last edited + + + {renderLastUpdateDate(attr)} - - Actions + + onEditAttribute(attr)} + > + + + onDeleteAttribute(attr)} + > + + - - - - {attributes.map(attr => ( - - - - {renderAttributeTitle(attr)} - - - - - {renderAttributeValue(attr)} - - - - - {renderLastUpdateDate(attr)} - - - - onEditAttribute(attr)} - > - - - onDeleteAttribute(attr)} - > - - - - - ))} - -
-
-
-
- - - - - + + ))} + + -
+
+
+ +
); From 6eca2aeb560b35099e09903c4a13e6b06ab5262a Mon Sep 17 00:00:00 2001 From: designhorf Date: Thu, 3 Oct 2019 11:05:35 +0200 Subject: [PATCH 194/207] fix: spaces on Dashboard header --- src/renderer/corporate/dashboard/dashboard-page.jsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/renderer/corporate/dashboard/dashboard-page.jsx b/src/renderer/corporate/dashboard/dashboard-page.jsx index 881fdd5a3..0acdb21de 100644 --- a/src/renderer/corporate/dashboard/dashboard-page.jsx +++ b/src/renderer/corporate/dashboard/dashboard-page.jsx @@ -10,8 +10,8 @@ const styles = theme => ({ title: { padding: '0' }, - contentContainer: { - borderBottom: '1px solid #303C49' + header: { + marginBottom: '45px' } }); class CorporateDashboardPage extends CorporateComponent { @@ -35,7 +35,7 @@ class CorporateDashboardPage extends CorporateComponent { alignItems="stretch" className={classes.container} > - + SelfKey Corporate Wallet From 330229378cc790159e1310f51dc97c7d8862aaf4 Mon Sep 17 00:00:00 2001 From: designhorf Date: Thu, 3 Oct 2019 13:02:29 +0200 Subject: [PATCH 195/207] fix: updated Selfkey UI --- package.json | 2 +- yarn.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 2808beaf3..e2210464d 100644 --- a/package.json +++ b/package.json @@ -114,7 +114,7 @@ "reselect": "4.0.0", "sanitize-html": "1.20.0", "scrypt": "6.0.3", - "selfkey-ui": "https://github.com/SelfKeyFoundation/selfkey-ui.git#f87ee8f6dd6328af28c6985115b669ba94f2002c", + "selfkey-ui": "https://github.com/SelfKeyFoundation/selfkey-ui.git#fee59787132eafe315352b9d21e95cc7b448a422", "selfkey.js": "1.0.24", "serialize-error": "3.0.0", "snyk": "1.216.0", diff --git a/yarn.lock b/yarn.lock index f4bce3d70..c445aa931 100644 --- a/yarn.lock +++ b/yarn.lock @@ -19024,9 +19024,9 @@ select@^1.1.2: react-truncate "2.4.0" reset-jss "1.0.0" -"selfkey-ui@https://github.com/SelfKeyFoundation/selfkey-ui.git#f87ee8f6dd6328af28c6985115b669ba94f2002c": +"selfkey-ui@https://github.com/SelfKeyFoundation/selfkey-ui.git#fee59787132eafe315352b9d21e95cc7b448a422": version "1.0.0" - resolved "https://github.com/SelfKeyFoundation/selfkey-ui.git#f87ee8f6dd6328af28c6985115b669ba94f2002c" + resolved "https://github.com/SelfKeyFoundation/selfkey-ui.git#fee59787132eafe315352b9d21e95cc7b448a422" dependencies: "@material-ui/core" "3.9.2" "@material-ui/icons" "3.0.2" From 512de7d80ff2fda7367329dc9758ef971b5782e2 Mon Sep 17 00:00:00 2001 From: designhorf Date: Thu, 3 Oct 2019 15:15:35 +0200 Subject: [PATCH 196/207] fix: changed style of organization chart --- src/renderer/corporate/common/corporate-org-chart.jsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/renderer/corporate/common/corporate-org-chart.jsx b/src/renderer/corporate/common/corporate-org-chart.jsx index 8761a8b9c..5e687fa55 100644 --- a/src/renderer/corporate/common/corporate-org-chart.jsx +++ b/src/renderer/corporate/common/corporate-org-chart.jsx @@ -1,6 +1,6 @@ import React from 'react'; import { Grid, CardHeader, Card, CardContent, withStyles } from '@material-ui/core'; -import { grey, EditTransparentIcon } from 'selfkey-ui'; +import { grey, EditTransparentIcon, typography } from 'selfkey-ui'; import 'react-orgchart/index.css'; import OrgChart from 'react-orgchart'; @@ -29,6 +29,7 @@ const styles = theme => ({ overflow: 'scroll', margin: 'auto', '& .initechNode': { + backgroundColor: '#313D49', border: `solid 1px ${grey}`, borderRadius: '3px', padding: '1em', @@ -39,7 +40,7 @@ const styles = theme => ({ }, '& .initechNode span': { display: 'block', - color: `${grey}`, + color: `${typography}`, fontSize: '12px', marginTop: '0.5em' }, From b8f13c8762020e534afae4250c146c31e0272e79 Mon Sep 17 00:00:00 2001 From: Maxim Kovalov Date: Fri, 4 Oct 2019 18:46:14 +0300 Subject: [PATCH 197/207] feat(corporate-wizard): validation WIP --- src/common/identity/selectors.js | 43 ++++++++- .../wizard/corporate-wizard-container.jsx | 87 ++++++++++++++----- .../corporate/wizard/corporate-wizard.jsx | 35 +++++++- 3 files changed, 140 insertions(+), 25 deletions(-) diff --git a/src/common/identity/selectors.js b/src/common/identity/selectors.js index e42e6c5da..296f277f6 100644 --- a/src/common/identity/selectors.js +++ b/src/common/identity/selectors.js @@ -239,6 +239,46 @@ const selectCurrentCorporateProfile = state => { return identitySelectors.selectCorporateProfile(state, identity.id); }; +const selectBasicCorporateAttributeTypes = state => { + let map = BASIC_CORPORATE_ATTRIBUTES; + + let allTypes = selectIdAttributeTypes(state, 'corporate'); + + return allTypes + .filter(t => map[t.url]) + .reduce((acc, curr) => { + curr = { ...curr }; + switch (curr.url) { + case EMAIL_ATTRIBUTE: + acc.email = curr; + curr.required = false; + return acc; + case TAX_ID: + acc.taxId = curr; + curr.required = false; + return acc; + case ENTITY_NAME: + acc.entityName = curr; + curr.required = true; + return acc; + case ENTITY_TYPE: + acc.entityType = curr; + curr.required = true; + return acc; + case CREATION_DATE: + acc.creationDate = curr; + curr.required = true; + return acc; + case JURISDICTION: + acc.jurisdiction = curr; + curr.required = true; + return acc; + default: + return acc; + } + }, {}); +}; + const selectCorporateProfile = (state, id) => { const identity = identitySelectors.selectIdentityById(state, id); if (!identity) return {}; @@ -307,7 +347,8 @@ export const identitySelectors = { selectCorporateJurisdictions, selectCorporateLegalEntityTypes, selectCorporateProfile, - selectCurrentCorporateProfile + selectCurrentCorporateProfile, + selectBasicCorporateAttributeTypes }; export default identitySelectors; diff --git a/src/renderer/corporate/wizard/corporate-wizard-container.jsx b/src/renderer/corporate/wizard/corporate-wizard-container.jsx index e729da4c2..c97b5198e 100644 --- a/src/renderer/corporate/wizard/corporate-wizard-container.jsx +++ b/src/renderer/corporate/wizard/corporate-wizard-container.jsx @@ -4,14 +4,17 @@ import { connect } from 'react-redux'; import { appSelectors } from 'common/app'; import { CorporateWizard } from './corporate-wizard'; import { push } from 'connected-react-router'; +import { identityAttributes } from 'common/identity/utils'; import { identityOperations, identitySelectors } from 'common/identity'; +const fields = ['jurisdiction', 'taxId', 'entityType', 'email', 'entityName', 'creationDate']; + class CorporateWizardContainerComponent extends Component { constructor(props) { super(props); const { basicIdentity = {} } = props; this.state = { - errors: {}, + errors: { hasErrors: false }, jurisdiction: basicIdentity.jurisdiction || '', taxId: basicIdentity.taxId || null, entityType: basicIdentity.entityType || '', @@ -34,34 +37,79 @@ class CorporateWizardContainerComponent extends Component { } handleFieldChange = name => evt => { - const errors = { ...this.state.errors }; let value = evt; + if (evt && evt.target) { value = evt.target.value; } - if (name === 'email') { - errors.email = value && !this.isValidEmail(value) ? 'Invalid email' : null; - } + const stateErrors = { ...this.state.errors }; + delete stateErrors[name]; + const errors = this.validateAllAttributes([{ name, value }]); + this.setState({ - errors, [name]: value }); + this.setErrors(errors); }; + setErrors(errors) { + const hasErrors = Object.keys(errors).length > 1; + this.setState({ + errors: { ...errors, hasErrors } + }); + } + + validateAllAttributes(attrs) { + const errorText = { + email: 'Email provided is invalid', + jurisdiction: 'Please select a jurisdiction', + entityName: 'Please enter an entity name', + entityType: 'Please select a entity type', + creationDate: 'Please enter company creation date', + taxId: 'Tax id provided is invalid' + }; + if (!attrs) { + attrs = fields.map(name => ({ name, value: this.state[name] })); + } + const errors = attrs.reduce( + (acc, curr) => { + const { name, value } = curr; + const isError = !this.isValidAttribute(name, value); + + if (isError) { + acc[name] = errorText[name]; + acc.hasErrors = true; + } + }, + { hasErrors: false } + ); + + return errors; + } + + isValidAttribute(name, value) { + const { basicAttributeTypes } = this.props; + const type = basicAttributeTypes[name]; + if (!type || !type.content) { + throw new Error('Not a basic attribute'); + } + if (type.required && !value) { + return false; + } + return identityAttributes.validate(type.content, { value }, []); + } + handleContinueClick = evt => { evt && evt.preventDefault(); + + const errors = this.validateAllAttributes(); + + if (errors.hasError) return; + this.props.dispatch( identityOperations.createCorporateProfileOperation({ - ..._.pick( - this.state, - 'jurisdiction', - 'taxId', - 'entityType', - 'email', - 'entityName', - 'creationDate' - ), + ..._.pick(this.state, fields), identityId: this.props.match.params.identityId }) ); @@ -78,13 +126,7 @@ class CorporateWizardContainerComponent extends Component { }; isDisabled() { - return ( - !this.state.jurisdiction || - !this.state.entityType || - !this.state.entityName || - !this.state.creationDate || - (this.state.email && !this.isValidEmail(this.state.email)) - ); + return this.state.errors.hasErrors; } render() { @@ -152,6 +194,7 @@ class CorporateWizardContainerComponent extends Component { const mapStateToProps = (state, props) => { return { + basicAttributeTypes: identitySelectors.selectBasicCorporateAttributeTypes(state), basicIdentity: identitySelectors.selectCorporateProfile( state, props.match.params.identityId diff --git a/src/renderer/corporate/wizard/corporate-wizard.jsx b/src/renderer/corporate/wizard/corporate-wizard.jsx index c66acab2c..ab92ec8c7 100644 --- a/src/renderer/corporate/wizard/corporate-wizard.jsx +++ b/src/renderer/corporate/wizard/corporate-wizard.jsx @@ -132,6 +132,7 @@ const CompanyInformation = withStyles(styles)(props => { className={classes.select} onChange={onFieldChange('jurisdiction')} displayEmpty + error={errors.jurisdiction} name="jurisdiction" value={jurisdiction} disableUnderline @@ -147,6 +148,11 @@ const CompanyInformation = withStyles(styles)(props => { ))} + {errors.jurisdiction && ( + + {errors.jurisdiction} + + )}
@@ -154,10 +160,16 @@ const CompanyInformation = withStyles(styles)(props => { id="entityName" fullWidth required + error={errors.entityName} value={entityName} onChange={onFieldChange('entityName')} placeholder="Entity Name" /> + {errors.entityName && ( + + {errors.entityName} + + )}
@@ -168,6 +180,7 @@ const CompanyInformation = withStyles(styles)(props => { onChange={onFieldChange('entityType')} value={entityType} name="entitytype" + error={errors.entityType} disableUnderline IconComponent={KeyboardArrowDown} input={} @@ -181,6 +194,11 @@ const CompanyInformation = withStyles(styles)(props => { ))} + {errors.entityType && ( + + {errors.entityType} + + )}
@@ -188,6 +206,7 @@ const CompanyInformation = withStyles(styles)(props => { id="creationDate" value={creationDate} required + error={errors.creationDate} onChange={onFieldChange('creationDate')} className={classes.picker} style={{ @@ -196,6 +215,11 @@ const CompanyInformation = withStyles(styles)(props => { } }} /> + {errors.creationDate && ( + + {errors.creationDate} + + )}
@@ -212,7 +236,7 @@ const CompanyInformation = withStyles(styles)(props => { /> {errors.email && ( - {'Email provided is invalid'} + {errors.email} )}
@@ -222,10 +246,16 @@ const CompanyInformation = withStyles(styles)(props => { id="taxId" fullWidth value={taxId} + error={errors.taxId} type="text" onChange={onFieldChange('taxId')} placeholder="Tax Payer ID" /> + {errors.taxId && ( + + {errors.taxId} + + )}
@@ -361,7 +391,7 @@ const CompanyInformation = withStyles(styles)(props => { class CorporateWizardComponent extends Component { render() { - const { classes } = this.props; + const { classes, isDisabled } = this.props; return (
@@ -376,6 +406,7 @@ class CorporateWizardComponent extends Component {