From 481fb0ded1fe06aed1b35543b80685655a00b5d8 Mon Sep 17 00:00:00 2001 From: kyranjamie Date: Tue, 15 Oct 2019 14:50:55 +0200 Subject: [PATCH 01/19] feat: Better UX of payment details form, update status icon --- components/maker/index.js | 1 - components/maker/payment/content.js | 51 +++++++++ components/maker/payment/helpers.js | 36 +++++++ components/maker/payment/index.js | 158 ++++++++++------------------ components/maker/status/index.js | 6 +- pages/all.js | 23 ++-- pages/maker/index.js | 52 ++++++++- 7 files changed, 204 insertions(+), 123 deletions(-) create mode 100644 components/maker/payment/content.js create mode 100644 components/maker/payment/helpers.js diff --git a/components/maker/index.js b/components/maker/index.js index 82a5c5c0..f84c5e70 100644 --- a/components/maker/index.js +++ b/components/maker/index.js @@ -5,7 +5,6 @@ import Status from './status' import Notification from './notification' import { SidebarButton } from './styled' - export default { SidebarButton, PaymentDetails, diff --git a/components/maker/payment/content.js b/components/maker/payment/content.js new file mode 100644 index 00000000..6f5256c4 --- /dev/null +++ b/components/maker/payment/content.js @@ -0,0 +1,51 @@ +import React from 'react' +import { Flex, Box, Type } from 'blockstack-ui' +import { MakerCardHeader, MakerCardText, MakerButton, MakerField } from '../styled' + +export const PaymentContainer = ({ children }) => ( + + + {children} + + +) + +export const PaymentHeader = MakerCardHeader + +export const PaymentDescription = () => ( + + This is where you will receive your App Mining payments. + Currently, payments are made in Bitcoin (BTC). Payments will be made + in Stacks (STX) in the future. + +) + +export const PaymentHelpText = () => ( + + {"Don't"} have a Stacks address? Download the Stacks wallet to get one + +) + +export const PaymentBtcField = props => ( + +) + +export const PaymentStxField = props => ( + +) + +export const PaymentButton = ({ children, ...props }) => ( + + {children} + +) diff --git a/components/maker/payment/helpers.js b/components/maker/payment/helpers.js new file mode 100644 index 00000000..412b7274 --- /dev/null +++ b/components/maker/payment/helpers.js @@ -0,0 +1,36 @@ +import { address, networks } from 'bitcoinjs-lib' +import * as c32Check from 'c32check' +import memoize from 'lodash/memoize' + +export const validateBTC = memoize(addr => { + try { + address.toOutputScript(addr, networks.bitcoin) + return true + } catch (error) { + return false + } +}) + +export const validateSTX = memoize(addr => { + try { + c32Check.c32addressDecode(addr) + return true + } catch (error) { + return false + } +}) + +export const savePaymentDetails = async ({ apiServer, appId, jwt, btcAddress, stxAddress }) => { + const response = await fetch(`${apiServer}/api/maker/apps?appId=${appId}`, { + method: 'POST', + headers: new Headers({ + 'Content-Type': 'application/json', + authorization: `Bearer ${jwt}` + }), + body: JSON.stringify({ + BTCAddress: btcAddress, + stacksAddress: stxAddress + }) + }) + await response.json() +} diff --git a/components/maker/payment/index.js b/components/maker/payment/index.js index f7f402d6..69943316 100644 --- a/components/maker/payment/index.js +++ b/components/maker/payment/index.js @@ -1,117 +1,75 @@ import React, { useState } from 'react' -import { Flex, Box, Type } from 'blockstack-ui' -import { address, networks } from 'bitcoinjs-lib' -import * as c32Check from 'c32check' -import Notification from '../notification' - +import { validateBTC, validateSTX, savePaymentDetails } from './helpers' import { - MakerCardHeader, - MakerCardText, - MakerButton, - MakerField -} from '../styled' - -const validateBTC = (addr) => { - try { - address.toOutputScript(addr, networks.bitcoin) - return true - } catch (error) { - return false - } -} - -const validateSTX = (addr) => { - try { - c32Check.c32addressDecode(addr) - return true - } catch (error) { - return false - } -} + PaymentContainer, + PaymentHeader, + PaymentDescription, + PaymentHelpText, + PaymentBtcField, + PaymentStxField, + PaymentButton +} from './content' -const PaymentDetails = ({ app, apiServer, accessToken, user }) => { +const PaymentDetails = ({ app, apiServer, accessToken, user, onPaymentDetailsComplete }) => { const [btcAddress, setBTCAddress] = useState(app.BTCAddress) const [stxAddress, setSTXAddress] = useState(app.stacksAddress) - const [showNotification, setShowNotification] = useState(false) - const [btcValid, setBtcValid] = useState(true) - const [stxValid, setStxValid] = useState(true) const [saving, setSaving] = useState(false) + const [hasAttemptedSaved, setHasAttemptedSaved] = useState(false) + const [savedValues, setSavedValue] = useState({ btcAddress, stxAddress }) - const notify = () => { - setShowNotification(true) - setTimeout(() => { - setShowNotification(false) - }, 10000) - } + const isSaved = ( + btcAddress === savedValues.btcAddress && + btcAddress !== '' && + stxAddress === savedValues.stxAddress && + stxAddress !== '' + ) const save = async () => { - let isValid = true - if (!validateBTC(btcAddress)) { - isValid = false - setBtcValid(false) - } - if (!validateSTX(stxAddress)) { - isValid = false - setStxValid(false) - } - if (!isValid) { - return - } else { - setBtcValid(true) - setStxValid(true) - } + setHasAttemptedSaved(true) + if (!validateBTC(btcAddress) || !validateSTX(stxAddress)) return setSaving(true) - console.log(stxAddress) - const response = await fetch(`${apiServer}/api/maker/apps?appId=${app.id}`, { - method: 'POST', - headers: new Headers({ - 'Content-Type': 'application/json', - authorization: `Bearer ${user.jwt}` - }), - body: JSON.stringify({ - BTCAddress: btcAddress, - stacksAddress: stxAddress - }) - }) - await response.json() - notify() + await savePaymentDetails({ apiServer, appId: app.id, jwt: user.jwt, btcAddress, stxAddress }) setSaving(false) + setSavedValue({ btcAddress, stxAddress }) + onPaymentDetailsComplete() + } + + const buttonText = () => { + if (saving) return 'Saving…' + if (isSaved) return 'Saved' + return 'Save' + } + + const createInputError = ({ validateFn, currencySymbol }) => addressHash => { + if (!hasAttemptedSaved) return null + if (!validateFn(addressHash)) return `Please enter a valid ${currencySymbol} address` + return null } + const getBtcError = createInputError({ validateFn: validateBTC, currencySymbol: 'BTC' }) + const getStxError = createInputError({ validateFn: validateSTX, currencySymbol: 'STX' }) return ( - - - Payment details - {showNotification && } - - This is where you will receive your App Mining payments. - Currently, payments are made in Bitcoin (BTC). Payments will be made - in Stacks (STX) in the future. - - setBTCAddress(e.target.value)} - value={btcAddress || ''} - error={!btcValid ? 'Please enter a valid BTC address' : null} - /> - setSTXAddress(e.target.value)} - value={stxAddress || ''} - error={!stxValid ? 'Please enter a valid STX address' : null} - /> - - {"Don't"} have a Stacks address? Download the Stacks wallet to get one - - save({ btcAddress, stxAddress, apiServer, accessToken })}> - {saving ? 'Saving...' : 'Save'} - - - + + Payment details + + setBTCAddress(e.target.value)} + value={btcAddress || ''} + error={getBtcError(btcAddress)} + /> + setSTXAddress(e.target.value)} + value={stxAddress || ''} + error={getStxError(stxAddress)} + /> + + save({ btcAddress, stxAddress, apiServer, accessToken })} + > + {buttonText()} + + ) } diff --git a/components/maker/status/index.js b/components/maker/status/index.js index bd02ebef..a0779692 100644 --- a/components/maker/status/index.js +++ b/components/maker/status/index.js @@ -60,7 +60,7 @@ const AppMiningIncomplete = () => ( ) -const Status = ({ app }) => { +const Status = ({ app, status }) => { const isReady = isMiningReady(app) return ( @@ -70,8 +70,8 @@ const Status = ({ app }) => { {isReady ? : } - - + + diff --git a/pages/all.js b/pages/all.js index 43c5c707..996c11af 100644 --- a/pages/all.js +++ b/pages/all.js @@ -4,19 +4,14 @@ import { AppsList } from '@components/list/apps' import Modal from '@containers/modals/app' import Head from '@containers/head' -class AllAppsPage extends React.PureComponent { - - render() { - return ( - - - - - - - - ) - } -} +const AllAppsPage = () => ( + + + + + + + +) export default AllAppsPage diff --git a/pages/maker/index.js b/pages/maker/index.js index fb8fd053..b3a7a50c 100644 --- a/pages/maker/index.js +++ b/pages/maker/index.js @@ -13,7 +13,12 @@ class MakerPortal extends React.Component { state = { loading: true, apps: [], - errorMessage: null + errorMessage: null, + status: { + paymentDetailsComplete: false, + kycComplete: false, + legalComplete: false + } } componentDidMount() { @@ -22,8 +27,10 @@ class MakerPortal extends React.Component { async fetchApps() { const { apiServer, user } = this.props + if (!(user && user.jwt)) { this.setState({ + ...this.state, loading: false, errorMessage: 'Please sign in to access the maker portal.' }) @@ -43,6 +50,22 @@ class MakerPortal extends React.Component { }) } + updateStatus (props) { + this.setState({ ...this.state, status: { ...this.state.status, ...props } }) + } + + setPaymentDetailsComplete () { + this.updateStatus({ paymentDetailsComplete: true }) + } + + setKycComplete () { + this.updateStatus({ kycComplete: true }) + } + + setLegalComplete () { + this.updateStatus({ legalComplete: true }) + } + render() { const { apiServer, user } = this.props @@ -70,17 +93,36 @@ class MakerPortal extends React.Component { - + - + this.setPaymentDetailsComplete()} + /> - + this.setKycComplete()} + /> - + this.setLegalComplete()} + /> From 21ce788b0431e3811f0330fcdaf14148392f4b80 Mon Sep 17 00:00:00 2001 From: kyranjamie Date: Wed, 16 Oct 2019 12:37:28 +0200 Subject: [PATCH 02/19] refactor: Create slice of state for maker portal --- components/maker/modal.js | 4 + components/maker/payment/helpers.js | 15 --- components/maker/payment/index.js | 8 +- pages/maker/index.js | 179 ++++++++++------------------ stores/index.js | 4 +- stores/maker/actions.js | 74 ++++++++++++ stores/maker/reducer.js | 61 ++++++++++ 7 files changed, 209 insertions(+), 136 deletions(-) create mode 100644 stores/maker/actions.js create mode 100644 stores/maker/reducer.js diff --git a/components/maker/modal.js b/components/maker/modal.js index 8d857dc3..e0e874c2 100644 --- a/components/maker/modal.js +++ b/components/maker/modal.js @@ -5,6 +5,10 @@ import styled from 'styled-components' import { CloseIcon } from '@components/svg/maker' const customStyles = { + overlay: { + // above headroom header library + zIndex: 100 + }, content : { top: '50%', left: '50%', diff --git a/components/maker/payment/helpers.js b/components/maker/payment/helpers.js index 412b7274..c59925d8 100644 --- a/components/maker/payment/helpers.js +++ b/components/maker/payment/helpers.js @@ -19,18 +19,3 @@ export const validateSTX = memoize(addr => { return false } }) - -export const savePaymentDetails = async ({ apiServer, appId, jwt, btcAddress, stxAddress }) => { - const response = await fetch(`${apiServer}/api/maker/apps?appId=${appId}`, { - method: 'POST', - headers: new Headers({ - 'Content-Type': 'application/json', - authorization: `Bearer ${jwt}` - }), - body: JSON.stringify({ - BTCAddress: btcAddress, - stacksAddress: stxAddress - }) - }) - await response.json() -} diff --git a/components/maker/payment/index.js b/components/maker/payment/index.js index 69943316..d2623f49 100644 --- a/components/maker/payment/index.js +++ b/components/maker/payment/index.js @@ -1,5 +1,6 @@ import React, { useState } from 'react' -import { validateBTC, validateSTX, savePaymentDetails } from './helpers' +import { savePaymentDetails } from '@stores/maker/actions' +import { validateBTC, validateSTX } from './helpers' import { PaymentContainer, PaymentHeader, @@ -10,7 +11,7 @@ import { PaymentButton } from './content' -const PaymentDetails = ({ app, apiServer, accessToken, user, onPaymentDetailsComplete }) => { +const PaymentDetails = ({ app, apiServer, accessToken, user, dispatch }) => { const [btcAddress, setBTCAddress] = useState(app.BTCAddress) const [stxAddress, setSTXAddress] = useState(app.stacksAddress) const [saving, setSaving] = useState(false) @@ -28,10 +29,9 @@ const PaymentDetails = ({ app, apiServer, accessToken, user, onPaymentDetailsCom setHasAttemptedSaved(true) if (!validateBTC(btcAddress) || !validateSTX(stxAddress)) return setSaving(true) - await savePaymentDetails({ apiServer, appId: app.id, jwt: user.jwt, btcAddress, stxAddress }) + await savePaymentDetails({ apiServer, appId: app.id, jwt: user.jwt, btcAddress, stxAddress })(dispatch) setSaving(false) setSavedValue({ btcAddress, stxAddress }) - onPaymentDetailsComplete() } const buttonText = () => { diff --git a/pages/maker/index.js b/pages/maker/index.js index b3a7a50c..a1ae2732 100644 --- a/pages/maker/index.js +++ b/pages/maker/index.js @@ -1,140 +1,87 @@ -import React from 'react' +import React, { useEffect } from 'react' import { Flex, Box, Type } from 'blockstack-ui' import { connect } from 'react-redux' +import { selectMaker } from '@stores/maker/reducer' +import { fetchApps } from '@stores/maker/actions' import { selectApiServer, selectUser } from '@stores/apps/selectors' import { Page } from '@components/page' import Head from '@containers/head' import Maker from '@components/maker' import { MakerContainer, MakerContentBox, MakerStickyStatusBox } from '@components/maker/styled' -class MakerPortal extends React.Component { - state = { - loading: true, - apps: [], - errorMessage: null, - status: { - paymentDetailsComplete: false, - kycComplete: false, - legalComplete: false - } - } - - componentDidMount() { - this.fetchApps() - } - - async fetchApps() { - const { apiServer, user } = this.props - - if (!(user && user.jwt)) { - this.setState({ - ...this.state, - loading: false, - errorMessage: 'Please sign in to access the maker portal.' - }) - return - } - - const uri = `${apiServer}/api/maker/apps` - const response = await fetch(uri, { - headers: { - Authorization: `Bearer ${user.jwt}` - } - }) - const { apps } = await response.json() - this.setState({ - loading: false, - apps - }) - } - - updateStatus (props) { - this.setState({ ...this.state, status: { ...this.state.status, ...props } }) - } - - setPaymentDetailsComplete () { - this.updateStatus({ paymentDetailsComplete: true }) - } - - setKycComplete () { - this.updateStatus({ kycComplete: true }) - } - - setLegalComplete () { - this.updateStatus({ legalComplete: true }) - } +const MakerPortal = ({ apiServer, user, maker, loading, errorMessage, dispatch }) => { - render() { - const { apiServer, user } = this.props - - const { loading, errorMessage, apps } = this.state - const [app] = apps // TODO: this is for now until we handle multiple apps - - if (loading || errorMessage) { - return ( - - - - {loading ? 'Loading...' : errorMessage} - - - - ) - } + useEffect(() => { + fetchApps({ apiServer, user })(dispatch) + }, []) + const app = maker.appEntities[maker.appIds[0]] + if (loading || !app) { return ( - - - - {app.name} - - - - - - - - this.setPaymentDetailsComplete()} - /> - - - this.setKycComplete()} - /> - - - this.setLegalComplete()} - /> - - - - + + + {loading ? 'Loading...' : errorMessage} + + ) } + console.log(app) + return ( + + + + + {app.name} + + + + + + + + dispatch(setPaymentDetailsComplete())} + /> + + + dispatch(setKycComplete())} + /> + + + dispatch(setLegalComplete())} + /> + + + + + + ) } const mapStateToProps = (state) => ({ user: selectUser(state), - apiServer: selectApiServer(state) + apiServer: selectApiServer(state), + maker: selectMaker(state) }) export default connect(mapStateToProps)(MakerPortal) diff --git a/stores/index.js b/stores/index.js index 6c24d38a..ee8a36d5 100644 --- a/stores/index.js +++ b/stores/index.js @@ -8,6 +8,7 @@ import newsletter from '@stores/newsletter' import RouterStore from '@stores/router' import makeMiningReducer from '@stores/mining/reducer' import AdminMiningReducer from '@stores/mining-admin/reducer' +import makerReducer from '@stores/maker/reducer' export default (data) => { const composeEnhancers = (typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) || compose @@ -21,7 +22,8 @@ export default (data) => { newsletter, router: RouterStore.reducer, mining: makeMiningReducer(data), - miningAdmin: AdminMiningReducer + miningAdmin: AdminMiningReducer, + maker: makerReducer }) return finalCreateStore(Reducer) diff --git a/stores/maker/actions.js b/stores/maker/actions.js new file mode 100644 index 00000000..6e7abb66 --- /dev/null +++ b/stores/maker/actions.js @@ -0,0 +1,74 @@ +export const SET_LOADING_DONE = '[Maker Page] SET_LOADING_DONE' +export const MAKER_AUTH_ERROR = '[Maker Page] MAKER_AUTH_ERROR' + +export const SET_PAYMENT_DETAILS_COMPLETE = '[Maker Page] SET_PAYMENT_DETAILS_COMPLETE' +export const SAVE_PAYMENT_DETAILS = '[Maker Page] SAVE_PAYMENT_DETAILS' +export const SAVE_PAYMENT_DETAILS_DONE = '[Maker Page] SAVE_PAYMENT_DETAILS_DONE' +export const SAVE_PAYMENT_DETAILS_FAIL = '[Maker Page] SAVE_PAYMENT_DETAILS_FAIL' + +export const SET_KYC_COMPLETE = '[Maker Page] SET_KYC_COMPLETE' +export const SET_LEGAL_COMPLETE = '[Maker Page] SET_LEGAL_COMPLETE' + +export const FETCH_APPS = '[Maker Page] FETCH_APPS' +export const FETCH_APPS_DONE = '[Maker Page] FETCH_APPS_DONE' +export const FETCH_APPS_FAIL = '[Maker Page] FETCH_APPS_FAIL' + +export const errorAction = () => ({ type: MAKER_AUTH_ERROR }) +export const setLoadingDoneAction = () => ({ type: SET_LOADING_DONE }) +export const setPaymentDetailsComplete = () => ({ type: SET_PAYMENT_DETAILS_COMPLETE }) +export const savePaymentDetailsAction = () => ({ type: SAVE_PAYMENT_DETAILS }) +export const savePaymentDetailsDoneAction = () => ({ type: SAVE_PAYMENT_DETAILS_DONE }) +export const savePaymentDetailsFailAction = () => ({ type: SAVE_PAYMENT_DETAILS_FAIL }) + +export const setKycComplete = () => ({ type: SET_KYC_COMPLETE }) +export const setLegalComplete = () => ({ type: SET_LEGAL_COMPLETE }) + +export const fetchAppsAction = () => ({ type: FETCH_APPS }) +export const fetchAppsDoneAction = payload => ({ type: FETCH_APPS_DONE, payload }) +export const fetchAppsFailAction = () => ({ type: FETCH_APPS_FAIL }) + + +export const savePaymentDetails = ({ apiServer, appId, jwt, btcAddress, stxAddress }) => async dispatch => { + dispatch(savePaymentDetailsAction()) + try { + const response = await fetch(`${apiServer}/api/maker/apps?appId=${appId}`, { + method: 'POST', + headers: new Headers({ + 'Content-Type': 'application/json', + authorization: `Bearer ${jwt}` + }), + body: JSON.stringify({ + BTCAddress: btcAddress, + stacksAddress: stxAddress + }) + }) + await response.json() + dispatch(setPaymentDetailsComplete()) + dispatch(savePaymentDetailsDoneAction()) + } catch (error) { + dispatch(savePaymentDetailsFailAction(error)) + } +} + + +export const fetchApps = ({ user, apiServer }) => async dispatch => { + dispatch(fetchAppsAction()) + if (!(user && user.jwt)) { + dispatch(errorAction()) + return + } + try { + const uri = `${apiServer}/api/maker/apps` + const response = await fetch(uri, { + headers: { + Authorization: `Bearer ${user.jwt}` + } + }) + const apps = await response.json() + dispatch(fetchAppsDoneAction(apps)) + dispatch(setLoadingDoneAction()) + } catch (error) { + dispatch(fetchAppsFailAction()) + } +} + diff --git a/stores/maker/reducer.js b/stores/maker/reducer.js new file mode 100644 index 00000000..263d0427 --- /dev/null +++ b/stores/maker/reducer.js @@ -0,0 +1,61 @@ +import { keyBy } from 'lodash' +import * as MakerActions from './actions' + +const initialState = { + loading: true, + apps: [], + appIds: [], + appEntities: {}, + errorMessage: null, + status: { + paymentDetailsComplete: false, + kycComplete: false, + legalComplete: false + } +} + +const updateStatus = (state, props) => ({ + ...state, + status: { ...state.status, ...props } +}) + +function makerReducer(state = initialState, action) { + switch (action.type) { + case MakerActions.SET_LOADING_DONE: + return { + ...state, + loading: false + } + + case MakerActions.MAKER_AUTH_ERROR: + return { + ...state, + loading: false, + errorMessage: 'Please sign in to access the maker portal.' + } + + case MakerActions.FETCH_APPS_DONE: + return { + ...state, + appIds: action.payload.apps.map(app => app.id), + appEntities: keyBy(action.payload.apps, 'id') + } + + case MakerActions.SET_PAYMENT_DETAILS_COMPLETE: + return updateStatus(state, { paymentDetailsComplete: true }) + + case MakerActions.SET_KYC_COMPLETE: + return updateStatus(state, { kycComplete: true }) + + case MakerActions.SET_LEGAL_COMPLETE: + return updateStatus(state, { legalComplete: true }) + + default: + return state + } +} + +export default makerReducer + +export const selectMaker = state => state.maker +export const selectAppList = state => state.maker.appIds.map(id => state.maker.appEntities[id]) From 04fea9cd6d79108a4569f7fc62fdbdb3ab539f57 Mon Sep 17 00:00:00 2001 From: kyranjamie Date: Wed, 16 Oct 2019 15:04:13 +0200 Subject: [PATCH 03/19] fix: Errors on Submit pageP --- components/maker/styled.js | 8 +++++++ pages/submit.js | 43 ++++++++++++++++---------------------- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/components/maker/styled.js b/components/maker/styled.js index 3a4957e1..30b2904f 100644 --- a/components/maker/styled.js +++ b/components/maker/styled.js @@ -54,6 +54,14 @@ export const MakerContainer = ({ children }) => ( ) +export const MakerTitle = styled(Type.h2)` + display: block; + font-weight: 500; + font-size: 24px; + line-height: 28px; + color: #0F1117; + margin-bottom: 16px; +` export const MakerCardHeader = styled(Type.h2)` font-weight: 500; diff --git a/pages/submit.js b/pages/submit.js index 1274151f..1582f650 100644 --- a/pages/submit.js +++ b/pages/submit.js @@ -4,10 +4,10 @@ import { connect } from 'react-redux' import Head from '@containers/head' import Link from 'next/link' import { bindActionCreators } from 'redux' +import { MakerTitle, MakerCardHeader, MakerCardText, MakerButton, MakerField } from '@components/maker/styled' import { Page } from '@components/page' import { Type, Field, Flex, Box, Button } from 'blockstack-ui' import { selectAppConstants, selectApiServer } from '@stores/apps/selectors' -import { string, boolean } from 'yup' import { FormSection, ErrorMessage, Bar, sections as getSections } from '@containers/submit' import debounce from 'lodash.debounce' import UserStore from '@stores/user' @@ -92,13 +92,8 @@ const Submit = ({ appConstants, setState, state, errors, submit, user, loading, return ( - Add an app to App.co - - Add any user-ready decentralized app: It could be an app you built, or an app you discovered. We manually - verify all information before publishing to App.co. Contact details are not displayed and we promise to keep - your information private and safe. - - + Submit your app + Personal details {user && user.user && ( @@ -121,19 +116,16 @@ const Submit = ({ appConstants, setState, state, errors, submit, user, loading, )}
- {sections.map((section) => ( - <> - - - + {sections.map(section => ( + ))} {errors ? : null} {!(user && user.jwt) ? ( @@ -141,10 +133,10 @@ const Submit = ({ appConstants, setState, state, errors, submit, user, loading, To submit your app, first login with Blockstack. You'll be able to use your Blockstack ID to manage your app's listing. - + {loading ? 'Loading...' : 'Login with Blockstack'} ) : ( - + {loading ? 'Loading...' : 'Submit App'} )}
@@ -260,12 +252,13 @@ class SubmitDapp extends React.Component { } render() { + // return
lkjsdflkjsdlfkjs
const { appConstants } = this.props return ( - + - + {this.state.success ? ( <> From c7c43f4f6c2d0b56eb0feb9cfecaec4def2c6556 Mon Sep 17 00:00:00 2001 From: kyranjamie Date: Thu, 17 Oct 2019 16:18:58 +0200 Subject: [PATCH 04/19] feat: Allow selection of different apps --- common/styles/index.js | 4 +-- components/submit/index.js | 32 ++++++++++++++++++ pages/maker/index.js | 29 ++++++++++++---- pages/submit.js | 68 ++++++++++++-------------------------- stores/maker/actions.js | 3 ++ stores/maker/reducer.js | 23 +++++++++++-- 6 files changed, 102 insertions(+), 57 deletions(-) create mode 100644 components/submit/index.js diff --git a/common/styles/index.js b/common/styles/index.js index 01118e1d..77065f1f 100644 --- a/common/styles/index.js +++ b/common/styles/index.js @@ -72,7 +72,7 @@ const theme = { accent: '#0CCABA' }), grey: Object.assign('#5B647C', { - light: '#E6E9EE', + light: '#F9F9FC', mid: '#7588A2', dark: '#142144' }), @@ -94,7 +94,7 @@ const wrapperStyle = css` padding-right: 20px; ${below.md` padding-left: 20px; - padding-right: 20px; + padding-right: 20px; `}; ` diff --git a/components/submit/index.js b/components/submit/index.js new file mode 100644 index 00000000..1cdf16e4 --- /dev/null +++ b/components/submit/index.js @@ -0,0 +1,32 @@ +import React from 'react' +import Link from 'next/link' +import { Type, Box, Button } from 'blockstack-ui' + +const SuccessCard = ({ isAppMiningEligible }) => ( + + + + Success! + + + + + Thanks for your submission! Your app will need to be approved before being public on app.co. + + {isAppMiningEligible && ( + <> + + To update your app's details and enroll in App Mining, visit our Maker Portal + + + + + + )} + + +) + +export default SuccessCard diff --git a/pages/maker/index.js b/pages/maker/index.js index a1ae2732..4b4e7d8e 100644 --- a/pages/maker/index.js +++ b/pages/maker/index.js @@ -2,22 +2,28 @@ import React, { useEffect } from 'react' import { Flex, Box, Type } from 'blockstack-ui' import { connect } from 'react-redux' -import { selectMaker } from '@stores/maker/reducer' -import { fetchApps } from '@stores/maker/actions' +import { selectMaker, selectAppList, selectCurrentApp } from '@stores/maker/reducer' +import { fetchApps, selectAppAction } from '@stores/maker/actions' import { selectApiServer, selectUser } from '@stores/apps/selectors' import { Page } from '@components/page' import Head from '@containers/head' import Maker from '@components/maker' import { MakerContainer, MakerContentBox, MakerStickyStatusBox } from '@components/maker/styled' - -const MakerPortal = ({ apiServer, user, maker, loading, errorMessage, dispatch }) => { +const MakerPortal = ({ apiServer, user, maker, loading, errorMessage, appList, selectedApp, dispatch }) => { useEffect(() => { fetchApps({ apiServer, user })(dispatch) }, []) - const app = maker.appEntities[maker.appIds[0]] + const app = selectedApp + + function handleChangingApp (event) { + event.persist() + const id = event.target.value + dispatch(selectAppAction(id)) + } + if (loading || !app) { return ( @@ -29,11 +35,18 @@ const MakerPortal = ({ apiServer, user, maker, loading, errorMessage, dispatch } ) } - console.log(app) + return ( + + + {app.name} @@ -81,7 +94,9 @@ const MakerPortal = ({ apiServer, user, maker, loading, errorMessage, dispatch } const mapStateToProps = (state) => ({ user: selectUser(state), apiServer: selectApiServer(state), - maker: selectMaker(state) + maker: selectMaker(state), + appList: selectAppList(state), + selectedApp: selectCurrentApp(state) }) export default connect(mapStateToProps)(MakerPortal) diff --git a/pages/submit.js b/pages/submit.js index 1582f650..cb925ace 100644 --- a/pages/submit.js +++ b/pages/submit.js @@ -2,13 +2,13 @@ import React from 'react' import 'isomorphic-unfetch' import { connect } from 'react-redux' import Head from '@containers/head' -import Link from 'next/link' import { bindActionCreators } from 'redux' -import { MakerTitle, MakerCardHeader, MakerCardText, MakerButton, MakerField } from '@components/maker/styled' +import { MakerTitle, MakerCardHeader, MakerButton } from '@components/maker/styled' import { Page } from '@components/page' -import { Type, Field, Flex, Box, Button } from 'blockstack-ui' +import { Type, Field, Flex, Box } from 'blockstack-ui' import { selectAppConstants, selectApiServer } from '@stores/apps/selectors' -import { FormSection, ErrorMessage, Bar, sections as getSections } from '@containers/submit' +import { FormSection, ErrorMessage, sections as getSections } from '@containers/submit' +import SuccessCard from '@components/submit' import debounce from 'lodash.debounce' import UserStore from '@stores/user' @@ -259,48 +259,24 @@ class SubmitDapp extends React.Component { - {this.state.success ? ( - <> - - - - Success! - - - - Thanks for your submission! Your app will need to be approved before being public on app.co. - {this.appMiningEligible() && ( - <> - To update your app's details and enroll in App Mining, visit our Maker Portal - - - - - )} - - - - ) : ( - this.setState(args), 100)} - state={this.state.values} - errors={this.state.errorCount > 0 && this.state.errors} - signIn={this.props.signIn} - user={this.props.user} - isAppMiningEligible={this.appMiningEligible()} - /> - )} + { + this.state.success + ? + : ( + this.setState(args), 100)} + state={this.state.values} + errors={this.state.errorCount > 0 && this.state.errors} + signIn={this.props.signIn} + user={this.props.user} + isAppMiningEligible={this.appMiningEligible()} + /> + ) + } ) diff --git a/stores/maker/actions.js b/stores/maker/actions.js index 6e7abb66..9e1ed12b 100644 --- a/stores/maker/actions.js +++ b/stores/maker/actions.js @@ -13,6 +13,8 @@ export const FETCH_APPS = '[Maker Page] FETCH_APPS' export const FETCH_APPS_DONE = '[Maker Page] FETCH_APPS_DONE' export const FETCH_APPS_FAIL = '[Maker Page] FETCH_APPS_FAIL' +export const SELECT_APP = '[Maker Page] SELECT_APP' + export const errorAction = () => ({ type: MAKER_AUTH_ERROR }) export const setLoadingDoneAction = () => ({ type: SET_LOADING_DONE }) export const setPaymentDetailsComplete = () => ({ type: SET_PAYMENT_DETAILS_COMPLETE }) @@ -27,6 +29,7 @@ export const fetchAppsAction = () => ({ type: FETCH_APPS }) export const fetchAppsDoneAction = payload => ({ type: FETCH_APPS_DONE, payload }) export const fetchAppsFailAction = () => ({ type: FETCH_APPS_FAIL }) +export const selectAppAction = payload => ({ type: SELECT_APP, payload }) export const savePaymentDetails = ({ apiServer, appId, jwt, btcAddress, stxAddress }) => async dispatch => { dispatch(savePaymentDetailsAction()) diff --git a/stores/maker/reducer.js b/stores/maker/reducer.js index 263d0427..8989f4b0 100644 --- a/stores/maker/reducer.js +++ b/stores/maker/reducer.js @@ -1,4 +1,4 @@ -import { keyBy } from 'lodash' +import keyBy from 'lodash/keyBy' import * as MakerActions from './actions' const initialState = { @@ -6,6 +6,7 @@ const initialState = { apps: [], appIds: [], appEntities: {}, + selectedAppId: null, errorMessage: null, status: { paymentDetailsComplete: false, @@ -38,7 +39,8 @@ function makerReducer(state = initialState, action) { return { ...state, appIds: action.payload.apps.map(app => app.id), - appEntities: keyBy(action.payload.apps, 'id') + appEntities: keyBy(action.payload.apps, 'id'), + selectedAppId: action.payload.apps.length ? action.payload.apps[0].id : null } case MakerActions.SET_PAYMENT_DETAILS_COMPLETE: @@ -50,6 +52,22 @@ function makerReducer(state = initialState, action) { case MakerActions.SET_LEGAL_COMPLETE: return updateStatus(state, { legalComplete: true }) + case MakerActions.SELECT_APP: + return { ...state, selectedAppId: action.payload } + + case MakerActions.SAVE_PAYMENT_DETAILS_DONE: + return { + ...state, + appEntities: { + ...state.appEntities, + [action.payload.id]: { + ...state.appEntities[action.payload.id], + BTCAddress: action.payload.btcAddress, + stacksAddress: action.payload.stxAddress + } + } + } + default: return state } @@ -59,3 +77,4 @@ export default makerReducer export const selectMaker = state => state.maker export const selectAppList = state => state.maker.appIds.map(id => state.maker.appEntities[id]) +export const selectCurrentApp = state => state.maker.appEntities[state.maker.selectedAppId] From e75a7ad7e4d4b87720cace6c5a79fef393d74a74 Mon Sep 17 00:00:00 2001 From: kyranjamie Date: Mon, 21 Oct 2019 10:52:22 -0700 Subject: [PATCH 05/19] refactor: Move selectors to their own file fix: CAN REBASE AMEND, Infer status from state feat: Infer status --- components/maker/status/index.js | 4 ++-- pages/maker/index.js | 12 ++++++------ stores/maker/actions.js | 11 +++++------ stores/maker/reducer.js | 30 ++++-------------------------- stores/maker/selectors.js | 23 +++++++++++++++++++++++ 5 files changed, 40 insertions(+), 40 deletions(-) create mode 100644 stores/maker/selectors.js diff --git a/components/maker/status/index.js b/components/maker/status/index.js index a0779692..630b372b 100644 --- a/components/maker/status/index.js +++ b/components/maker/status/index.js @@ -70,8 +70,8 @@ const Status = ({ app, status }) => { {isReady ? : } - - + + diff --git a/pages/maker/index.js b/pages/maker/index.js index 4b4e7d8e..6c1711db 100644 --- a/pages/maker/index.js +++ b/pages/maker/index.js @@ -2,7 +2,7 @@ import React, { useEffect } from 'react' import { Flex, Box, Type } from 'blockstack-ui' import { connect } from 'react-redux' -import { selectMaker, selectAppList, selectCurrentApp } from '@stores/maker/reducer' +import { selectMaker, selectAppList, selectCurrentApp, selectCompetionStatus } from '@stores/maker/selectors' import { fetchApps, selectAppAction } from '@stores/maker/actions' import { selectApiServer, selectUser } from '@stores/apps/selectors' import { Page } from '@components/page' @@ -12,9 +12,8 @@ import { MakerContainer, MakerContentBox, MakerStickyStatusBox } from '@componen const MakerPortal = ({ apiServer, user, maker, loading, errorMessage, appList, selectedApp, dispatch }) => { - useEffect(() => { - fetchApps({ apiServer, user })(dispatch) - }, []) +const MakerPortal = ({ query, params, apiServer, user, maker, errorMessage, appList, selectedApp, competionStatus, dispatch }) => { + console.log('Rendering component') const app = selectedApp @@ -55,7 +54,7 @@ const MakerPortal = ({ apiServer, user, maker, loading, errorMessage, appList, s @@ -96,7 +95,8 @@ const mapStateToProps = (state) => ({ apiServer: selectApiServer(state), maker: selectMaker(state), appList: selectAppList(state), - selectedApp: selectCurrentApp(state) + selectedApp: selectCurrentApp(state), + competionStatus: selectCompetionStatus(state) }) export default connect(mapStateToProps)(MakerPortal) diff --git a/stores/maker/actions.js b/stores/maker/actions.js index 9e1ed12b..62629158 100644 --- a/stores/maker/actions.js +++ b/stores/maker/actions.js @@ -17,9 +17,11 @@ export const SELECT_APP = '[Maker Page] SELECT_APP' export const errorAction = () => ({ type: MAKER_AUTH_ERROR }) export const setLoadingDoneAction = () => ({ type: SET_LOADING_DONE }) -export const setPaymentDetailsComplete = () => ({ type: SET_PAYMENT_DETAILS_COMPLETE }) export const savePaymentDetailsAction = () => ({ type: SAVE_PAYMENT_DETAILS }) -export const savePaymentDetailsDoneAction = () => ({ type: SAVE_PAYMENT_DETAILS_DONE }) +export const savePaymentDetailsDoneAction = addresses => ({ + type: SAVE_PAYMENT_DETAILS_DONE, + payload: addresses +}) export const savePaymentDetailsFailAction = () => ({ type: SAVE_PAYMENT_DETAILS_FAIL }) export const setKycComplete = () => ({ type: SET_KYC_COMPLETE }) @@ -46,14 +48,12 @@ export const savePaymentDetails = ({ apiServer, appId, jwt, btcAddress, stxAddre }) }) await response.json() - dispatch(setPaymentDetailsComplete()) - dispatch(savePaymentDetailsDoneAction()) + dispatch(savePaymentDetailsDoneAction({ appId, btcAddress, stxAddress })) } catch (error) { dispatch(savePaymentDetailsFailAction(error)) } } - export const fetchApps = ({ user, apiServer }) => async dispatch => { dispatch(fetchAppsAction()) if (!(user && user.jwt)) { @@ -74,4 +74,3 @@ export const fetchApps = ({ user, apiServer }) => async dispatch => { dispatch(fetchAppsFailAction()) } } - diff --git a/stores/maker/reducer.js b/stores/maker/reducer.js index 8989f4b0..8aed44ff 100644 --- a/stores/maker/reducer.js +++ b/stores/maker/reducer.js @@ -7,21 +7,12 @@ const initialState = { appIds: [], appEntities: {}, selectedAppId: null, - errorMessage: null, - status: { - paymentDetailsComplete: false, - kycComplete: false, - legalComplete: false - } + errorMessage: null } -const updateStatus = (state, props) => ({ - ...state, - status: { ...state.status, ...props } -}) - function makerReducer(state = initialState, action) { switch (action.type) { + case MakerActions.SET_LOADING_DONE: return { ...state, @@ -43,15 +34,6 @@ function makerReducer(state = initialState, action) { selectedAppId: action.payload.apps.length ? action.payload.apps[0].id : null } - case MakerActions.SET_PAYMENT_DETAILS_COMPLETE: - return updateStatus(state, { paymentDetailsComplete: true }) - - case MakerActions.SET_KYC_COMPLETE: - return updateStatus(state, { kycComplete: true }) - - case MakerActions.SET_LEGAL_COMPLETE: - return updateStatus(state, { legalComplete: true }) - case MakerActions.SELECT_APP: return { ...state, selectedAppId: action.payload } @@ -60,8 +42,8 @@ function makerReducer(state = initialState, action) { ...state, appEntities: { ...state.appEntities, - [action.payload.id]: { - ...state.appEntities[action.payload.id], + [action.payload.appId]: { + ...state.appEntities[action.payload.appId], BTCAddress: action.payload.btcAddress, stacksAddress: action.payload.stxAddress } @@ -74,7 +56,3 @@ function makerReducer(state = initialState, action) { } export default makerReducer - -export const selectMaker = state => state.maker -export const selectAppList = state => state.maker.appIds.map(id => state.maker.appEntities[id]) -export const selectCurrentApp = state => state.maker.appEntities[state.maker.selectedAppId] diff --git a/stores/maker/selectors.js b/stores/maker/selectors.js new file mode 100644 index 00000000..1fdeb460 --- /dev/null +++ b/stores/maker/selectors.js @@ -0,0 +1,23 @@ +const updateEntity = (state, id, newProps) => ({ + ...state, + appEntities: { + ...state.appEntities, + [id]: { + ...state.appEntities[id], + ...newProps + } + } +}) + +export const selectMaker = state => state.maker + +export const selectAppList = state => state.maker.appIds.map(id => state.maker.appEntities[id]) + +export const selectCurrentApp = state => state.maker.appEntities[state.maker.selectedAppId] + +// export const selectCompetionStatus = state => { +// const selectedApp = state.appEntities[state.selectedAppId] +// return { +// paymentDetailsComplete +// } +// } From cdca8d11a6d5b09f39294587a5b7553c96490ec1 Mon Sep 17 00:00:00 2001 From: kyranjamie Date: Mon, 21 Oct 2019 14:13:25 -0700 Subject: [PATCH 06/19] fix: Point modal to app element --- components/maker/modal.js | 2 +- components/maker/status/index.js | 2 +- stores/maker/selectors.js | 17 +++++++++++------ 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/components/maker/modal.js b/components/maker/modal.js index e0e874c2..3669d56c 100644 --- a/components/maker/modal.js +++ b/components/maker/modal.js @@ -40,7 +40,7 @@ const MakerModal = ({ isOpen, handleClose, children }) => ( isOpen={isOpen} onRequestClose={handleClose} style={customStyles} - ariaHideApp={false} + appElement={document.querySelector('#__next')} > {children} diff --git a/components/maker/status/index.js b/components/maker/status/index.js index 630b372b..bd02ebef 100644 --- a/components/maker/status/index.js +++ b/components/maker/status/index.js @@ -60,7 +60,7 @@ const AppMiningIncomplete = () => ( ) -const Status = ({ app, status }) => { +const Status = ({ app }) => { const isReady = isMiningReady(app) return ( diff --git a/stores/maker/selectors.js b/stores/maker/selectors.js index 1fdeb460..82981440 100644 --- a/stores/maker/selectors.js +++ b/stores/maker/selectors.js @@ -15,9 +15,14 @@ export const selectAppList = state => state.maker.appIds.map(id => state.maker.a export const selectCurrentApp = state => state.maker.appEntities[state.maker.selectedAppId] -// export const selectCompetionStatus = state => { -// const selectedApp = state.appEntities[state.selectedAppId] -// return { -// paymentDetailsComplete -// } -// } +export const selectCompetionStatus = state => { + const selectedApp = state.maker.appEntities[state.maker.selectedAppId] + if (!selectedApp) { + return {} + } + return { + paymentDetailsComplete: selectedApp.BTCAddress && selectedApp.stacksAddress, + kycComplete: selectedApp.isKYCVerified, + legalComplete: false + } +} From edcbd66859a6da610d95974b74c88618716dd52c Mon Sep 17 00:00:00 2001 From: kyranjamie Date: Tue, 29 Oct 2019 11:08:20 +0000 Subject: [PATCH 07/19] fix: Merge error and missing dot --- pages/admin/app.js | 6 +-- pages/maker/index.js | 95 ++++++++++++++++++++++++++++++++------------ 2 files changed, 71 insertions(+), 30 deletions(-) diff --git a/pages/admin/app.js b/pages/admin/app.js index 1cadeb4b..d0b2d135 100644 --- a/pages/admin/app.js +++ b/pages/admin/app.js @@ -88,7 +88,7 @@ class App extends React.Component { async fetchApp() { const qs = queryString.parse(document.location.search) if (qs.id && this.props.jwt) { - const request = await fetch(`${this.propsapiServer}/api/admin/apps/${qs.id}`, { + const request = await fetch(`${this.props.apiServer}/api/admin/apps/${qs.id}`, { method: 'GET', headers: new Headers({ Authorization: `Bearer ${this.props.jwt}`, @@ -151,10 +151,6 @@ class App extends React.Component { // const app = this.props.selectedApp // const { name } = this.state; const app = this.state -<<<<<<< HEAD - const { categories, authentications, storageNetworks, blockchains } = this.props -======= ->>>>>>> origin/develop if (!app.name) { return

Loading

} diff --git a/pages/maker/index.js b/pages/maker/index.js index 6c1711db..b7470ed8 100644 --- a/pages/maker/index.js +++ b/pages/maker/index.js @@ -1,58 +1,106 @@ import React, { useEffect } from 'react' +import { useRouter } from 'next/router' import { Flex, Box, Type } from 'blockstack-ui' import { connect } from 'react-redux' +import isNaN from 'lodash/isNaN' import { selectMaker, selectAppList, selectCurrentApp, selectCompetionStatus } from '@stores/maker/selectors' import { fetchApps, selectAppAction } from '@stores/maker/actions' import { selectApiServer, selectUser } from '@stores/apps/selectors' +import { MakerContainer, MakerContentBox, MakerStickyStatusBox } from '@components/maker/styled' import { Page } from '@components/page' import Head from '@containers/head' import Maker from '@components/maker' -import { MakerContainer, MakerContentBox, MakerStickyStatusBox } from '@components/maker/styled' -const MakerPortal = ({ apiServer, user, maker, loading, errorMessage, appList, selectedApp, dispatch }) => { +const MakerPortal = ({ params, apiServer, user, maker, errorMessage, appList, selectedApp, competionStatus, dispatch }) => { -const MakerPortal = ({ query, params, apiServer, user, maker, errorMessage, appList, selectedApp, competionStatus, dispatch }) => { - console.log('Rendering component') + const hasAppId = params && !!params.appId - const app = selectedApp + const router = useRouter() - function handleChangingApp (event) { - event.persist() - const id = event.target.value - dispatch(selectAppAction(id)) + console.log(router) + const updateMakerRoute = id => { + router.push( + { + pathname: '/maker', + query: { + params: { appId: id } + }, + as: `/maker/${id}` + }, + { + shallow: true + } + ) + } + + const getAppId = () => { + + const id = parseInt(params.appId, 10) + if (isNaN(id)) return null + return id } - if (loading || !app) { + useEffect(() => { + async function fetchAppsOnInit () { + await fetchApps({ apiServer, user })(dispatch) + + if (hasAppId) { + dispatch(selectAppAction(getAppId())) + } + } + fetchAppsOnInit() + }, []) + + if (maker.loading || !selectedApp) { return ( - {loading ? 'Loading...' : errorMessage} + {maker.loading ? 'Loading...' : errorMessage} ) } + // if (!hasAppId) { + // if (appList.length === 0) throw new Error('wlkdsfsldfl') + // const { id } = appList[0] + // console.log('has no app id take first', id) + // updateMakerRoute(id) + // dispatch(selectAppAction(id)) + // } + + function handleChangingApp (event) { + event.persist() + const id = event.target.value + dispatch(selectAppAction(id)) + updateMakerRoute(id) + } + + return ( - + - + { + appList.length && + + } - {app.name} + {selectedApp.name} @@ -60,27 +108,24 @@ const MakerPortal = ({ query, params, apiServer, user, maker, errorMessage, appL dispatch(setPaymentDetailsComplete())} /> dispatch(setKycComplete())} /> dispatch(setLegalComplete())} /> From 0564524ac3e6ef7d88173ef586e7d1b96952efed Mon Sep 17 00:00:00 2001 From: kyranjamie Date: Tue, 29 Oct 2019 12:07:50 +0000 Subject: [PATCH 08/19] feat: Change routing to 'maker/apps' --- pages/admin/app.js | 4 +++ pages/maker/{ => apps}/index.js | 50 +++++++++++++++------------------ server.js | 7 +++-- stores/maker/actions.js | 5 ++-- stores/maker/reducer.js | 11 ++------ 5 files changed, 36 insertions(+), 41 deletions(-) rename pages/maker/{ => apps}/index.js (86%) diff --git a/pages/admin/app.js b/pages/admin/app.js index d0b2d135..540075ff 100644 --- a/pages/admin/app.js +++ b/pages/admin/app.js @@ -206,6 +206,10 @@ class App extends React.Component {

Magic link: {`/maker/${app.accessToken}`}

+

+ Maker portal: {`/maker/apps/${app.id}`} +

+ { - router.push( - { - pathname: '/maker', - query: { - params: { appId: id } - }, - as: `/maker/${id}` - }, - { - shallow: true - } - ) - } + const updateMakerRoute = id => router.push( + '/maker/apps', + `/maker/apps/${id}`, + { + shallow: true + } + ) const getAppId = () => { - + if (!params) return undefined const id = parseInt(params.appId, 10) - if (isNaN(id)) return null + if (isNaN(id)) return undefined return id } useEffect(() => { async function fetchAppsOnInit () { await fetchApps({ apiServer, user })(dispatch) - if (hasAppId) { dispatch(selectAppAction(getAppId())) } + if (!hasAppId && process.browser) { + setTimeout(() => { + console.log(appList) + const { id } = appList[0] + dispatch(selectAppAction(id)) + }) + } } fetchAppsOnInit() }, []) @@ -64,14 +62,6 @@ const MakerPortal = ({ params, apiServer, user, maker, errorMessage, appList, se ) } - // if (!hasAppId) { - // if (appList.length === 0) throw new Error('wlkdsfsldfl') - // const { id } = appList[0] - // console.log('has no app id take first', id) - // updateMakerRoute(id) - // dispatch(selectAppAction(id)) - // } - function handleChangingApp (event) { event.persist() const id = event.target.value @@ -79,7 +69,6 @@ const MakerPortal = ({ params, apiServer, user, maker, errorMessage, appList, se updateMakerRoute(id) } - return ( @@ -135,7 +124,12 @@ const MakerPortal = ({ params, apiServer, user, maker, errorMessage, appList, se ) } -const mapStateToProps = (state) => ({ +MakerPortal.getInitialProps = (x) => { + console.log(x.userApps) + return { params: x.query.params } +} + +const mapStateToProps = state => ({ user: selectUser(state), apiServer: selectApiServer(state), maker: selectMaker(state), diff --git a/server.js b/server.js index 4f9ae9b5..9014fb82 100644 --- a/server.js +++ b/server.js @@ -66,7 +66,8 @@ async function renderAndCache(req, res, pagePath, serverData) { ...serverData, blockstackRankedApps, appMiningMonths, - appMiningApps + appMiningApps, + params: req.params } const html = await app.renderToHTML(req, res, pagePath, dataToPass) if (cacheKey) { @@ -220,7 +221,9 @@ app.prepare().then(() => { /** * Maker pages */ - server.get('/maker', (req, res) => renderAndCache(req, res, '/maker')) + server.get('/maker', (req, res) => res.redirect('/maker/apps')) + server.get('/maker/apps', (req, res) => renderAndCache(req, res, '/maker/apps')) + server.get('/maker/apps/:appId', (req, res) => renderAndCache(req, res, '/maker/apps')) server.get('/maker/:accessToken', (req, res) => renderAndCache(req, res, '/maker/magic-link', { accessToken: req.params.accessToken })) apps.platforms.forEach((platform) => { diff --git a/stores/maker/actions.js b/stores/maker/actions.js index 62629158..f05b63c7 100644 --- a/stores/maker/actions.js +++ b/stores/maker/actions.js @@ -55,11 +55,11 @@ export const savePaymentDetails = ({ apiServer, appId, jwt, btcAddress, stxAddre } export const fetchApps = ({ user, apiServer }) => async dispatch => { - dispatch(fetchAppsAction()) if (!(user && user.jwt)) { dispatch(errorAction()) return } + dispatch(fetchAppsAction()) try { const uri = `${apiServer}/api/maker/apps` const response = await fetch(uri, { @@ -68,8 +68,7 @@ export const fetchApps = ({ user, apiServer }) => async dispatch => { } }) const apps = await response.json() - dispatch(fetchAppsDoneAction(apps)) - dispatch(setLoadingDoneAction()) + await dispatch(fetchAppsDoneAction(apps)) } catch (error) { dispatch(fetchAppsFailAction()) } diff --git a/stores/maker/reducer.js b/stores/maker/reducer.js index 8aed44ff..1fdad30a 100644 --- a/stores/maker/reducer.js +++ b/stores/maker/reducer.js @@ -13,12 +13,6 @@ const initialState = { function makerReducer(state = initialState, action) { switch (action.type) { - case MakerActions.SET_LOADING_DONE: - return { - ...state, - loading: false - } - case MakerActions.MAKER_AUTH_ERROR: return { ...state, @@ -29,9 +23,10 @@ function makerReducer(state = initialState, action) { case MakerActions.FETCH_APPS_DONE: return { ...state, + loading: false, appIds: action.payload.apps.map(app => app.id), - appEntities: keyBy(action.payload.apps, 'id'), - selectedAppId: action.payload.apps.length ? action.payload.apps[0].id : null + appEntities: keyBy(action.payload.apps, 'id') + // selectedAppId: action.payload.apps.length ? action.payload.apps[0].id : null } case MakerActions.SELECT_APP: From faca69f79924369a2ad70942eef2f7e0af09048d Mon Sep 17 00:00:00 2001 From: kyranjamie Date: Tue, 29 Oct 2019 13:01:07 +0000 Subject: [PATCH 09/19] feat: Add react-redux types --- package.json | 1 + pages/submit.js | 1 - yarn.lock | 36 +++++++++++++++++++++++++++++++++++- 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index f1e36928..3cd37d98 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "@mdx-js/tag": "^0.15.0", "@next/bundle-analyzer": "^9.0.6", "@next/mdx": "^9.0.6", + "@types/react-redux": "^7.1.5", "accounting": "^0.4.1", "async": "^2.6.0", "bitcoinjs-lib": "^5.0.5", diff --git a/pages/submit.js b/pages/submit.js index cb925ace..c65f58ba 100644 --- a/pages/submit.js +++ b/pages/submit.js @@ -252,7 +252,6 @@ class SubmitDapp extends React.Component { } render() { - // return
lkjsdflkjsdlfkjs
const { appConstants } = this.props return ( diff --git a/yarn.lock b/yarn.lock index b77b2a98..b89f41f1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2098,6 +2098,14 @@ dependencies: "@types/bn.js" "*" +"@types/hoist-non-react-statics@^3.3.0": + version "3.3.1" + resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f" + integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA== + dependencies: + "@types/react" "*" + hoist-non-react-statics "^3.3.0" + "@types/node@*": version "10.12.24" resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.24.tgz#b13564af612a22a20b5d95ca40f1bffb3af315cf" @@ -2118,6 +2126,24 @@ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.2.tgz#0e58ae66773d7fd7c372a493aff740878ec9ceaa" integrity sha512-f8JzJNWVhKtc9dg/dyDNfliTKNOJSLa7Oht/ElZdF/UbMUmAH3rLmAk3ODNjw0mZajDEgatA03tRjB4+Dp/tzA== +"@types/react-redux@^7.1.5": + version "7.1.5" + resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.5.tgz#c7a528d538969250347aa53c52241051cf886bd3" + integrity sha512-ZoNGQMDxh5ENY7PzU7MVonxDzS1l/EWiy8nUhDqxFqUZn4ovboCyvk4Djf68x6COb7vhGTKjyjxHxtFdAA5sUA== + dependencies: + "@types/hoist-non-react-statics" "^3.3.0" + "@types/react" "*" + hoist-non-react-statics "^3.3.0" + redux "^4.0.0" + +"@types/react@*": + version "16.9.11" + resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.11.tgz#70e0b7ad79058a7842f25ccf2999807076ada120" + integrity sha512-UBT4GZ3PokTXSWmdgC/GeCGEJXE5ofWyibCcecRLUVN2ZBpXQGVgQGtG2foS7CrTKFKlQVVswLvf7Js6XA/CVQ== + dependencies: + "@types/prop-types" "*" + csstype "^2.2.0" + "@types/react@^16.9.2": version "16.9.2" resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.2.tgz#6d1765431a1ad1877979013906731aae373de268" @@ -6628,7 +6654,7 @@ hoist-non-react-statics@^2.3.1, hoist-non-react-statics@^2.5.0, hoist-non-react- resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz#c5903cf409c0dfd908f388e619d86b9c1174cb47" integrity sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw== -hoist-non-react-statics@^3.1.0: +hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz#b09178f0122184fb95acf525daaecb4d8f45958b" integrity sha512-0XsbTXxgiaCDYDIWFcwkmerZPSwywfUqYmwT4jzewKTQSWoE6FCMoUVOeBJWK3E/CrWbxRG3m5GzY4lnIwGRBA== @@ -10794,6 +10820,14 @@ redux@^3.7.2: loose-envify "^1.1.0" symbol-observable "^1.0.3" +redux@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.4.tgz#4ee1aeb164b63d6a1bcc57ae4aa0b6e6fa7a3796" + integrity sha512-vKv4WdiJxOWKxK0yRoaK3Y4pxxB0ilzVx6dszU2W8wLxlb2yikRph4iV/ymtdJ6ZxpBLFbyrxklnT5yBbQSl3Q== + dependencies: + loose-envify "^1.4.0" + symbol-observable "^1.2.0" + redux@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.1.tgz#436cae6cc40fbe4727689d7c8fae44808f1bfef5" From 5a63a74d26e85251380761a6b4d8819bf7409d7f Mon Sep 17 00:00:00 2001 From: kyranjamie Date: Tue, 29 Oct 2019 13:26:02 +0000 Subject: [PATCH 10/19] refactor: Use app.co scoped action naming convention --- components/page/index.js | 2 +- stores/maker/actions.js | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/components/page/index.js b/components/page/index.js index 43d93b09..cd2eb60e 100644 --- a/components/page/index.js +++ b/components/page/index.js @@ -7,7 +7,7 @@ import { StyledPage } from './styled' const Page = ({ isErrorPage = false, children, admin = false, wrap, innerPadding = [2, 0], ...rest }) => ( - + {children} diff --git a/stores/maker/actions.js b/stores/maker/actions.js index f05b63c7..f4720e4e 100644 --- a/stores/maker/actions.js +++ b/stores/maker/actions.js @@ -1,19 +1,19 @@ -export const SET_LOADING_DONE = '[Maker Page] SET_LOADING_DONE' -export const MAKER_AUTH_ERROR = '[Maker Page] MAKER_AUTH_ERROR' +export const SET_LOADING_DONE = 'maker-page/SET_LOADING_DONE' +export const MAKER_AUTH_ERROR = 'maker-page/MAKER_AUTH_ERROR' -export const SET_PAYMENT_DETAILS_COMPLETE = '[Maker Page] SET_PAYMENT_DETAILS_COMPLETE' -export const SAVE_PAYMENT_DETAILS = '[Maker Page] SAVE_PAYMENT_DETAILS' -export const SAVE_PAYMENT_DETAILS_DONE = '[Maker Page] SAVE_PAYMENT_DETAILS_DONE' -export const SAVE_PAYMENT_DETAILS_FAIL = '[Maker Page] SAVE_PAYMENT_DETAILS_FAIL' +export const SET_PAYMENT_DETAILS_COMPLETE = 'maker-page/SET_PAYMENT_DETAILS_COMPLETE' +export const SAVE_PAYMENT_DETAILS = 'maker-page/SAVE_PAYMENT_DETAILS' +export const SAVE_PAYMENT_DETAILS_DONE = 'maker-page/SAVE_PAYMENT_DETAILS_DONE' +export const SAVE_PAYMENT_DETAILS_FAIL = 'maker-page/SAVE_PAYMENT_DETAILS_FAIL' -export const SET_KYC_COMPLETE = '[Maker Page] SET_KYC_COMPLETE' -export const SET_LEGAL_COMPLETE = '[Maker Page] SET_LEGAL_COMPLETE' +export const SET_KYC_COMPLETE = 'maker-page/SET_KYC_COMPLETE' +export const SET_LEGAL_COMPLETE = 'maker-page/SET_LEGAL_COMPLETE' -export const FETCH_APPS = '[Maker Page] FETCH_APPS' -export const FETCH_APPS_DONE = '[Maker Page] FETCH_APPS_DONE' -export const FETCH_APPS_FAIL = '[Maker Page] FETCH_APPS_FAIL' +export const FETCH_APPS = 'maker-page/FETCH_APPS' +export const FETCH_APPS_DONE = 'maker-page/FETCH_APPS_DONE' +export const FETCH_APPS_FAIL = 'maker-page/FETCH_APPS_FAIL' -export const SELECT_APP = '[Maker Page] SELECT_APP' +export const SELECT_APP = 'maker-page/SELECT_APP' export const errorAction = () => ({ type: MAKER_AUTH_ERROR }) export const setLoadingDoneAction = () => ({ type: SET_LOADING_DONE }) From 9705b583f37c999d64a1804953dc2b0e7da347dd Mon Sep 17 00:00:00 2001 From: Thomas Osmonson Date: Tue, 29 Oct 2019 17:26:28 -0500 Subject: [PATCH 11/19] adjust actions a bit --- stores/maker/actions.js | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/stores/maker/actions.js b/stores/maker/actions.js index f4720e4e..a2452c54 100644 --- a/stores/maker/actions.js +++ b/stores/maker/actions.js @@ -18,7 +18,7 @@ export const SELECT_APP = 'maker-page/SELECT_APP' export const errorAction = () => ({ type: MAKER_AUTH_ERROR }) export const setLoadingDoneAction = () => ({ type: SET_LOADING_DONE }) export const savePaymentDetailsAction = () => ({ type: SAVE_PAYMENT_DETAILS }) -export const savePaymentDetailsDoneAction = addresses => ({ +export const savePaymentDetailsDoneAction = (addresses) => ({ type: SAVE_PAYMENT_DETAILS_DONE, payload: addresses }) @@ -28,12 +28,14 @@ export const setKycComplete = () => ({ type: SET_KYC_COMPLETE }) export const setLegalComplete = () => ({ type: SET_LEGAL_COMPLETE }) export const fetchAppsAction = () => ({ type: FETCH_APPS }) -export const fetchAppsDoneAction = payload => ({ type: FETCH_APPS_DONE, payload }) + +export const fetchAppsDoneAction = (payload) => ({ type: FETCH_APPS_DONE, payload }) + export const fetchAppsFailAction = () => ({ type: FETCH_APPS_FAIL }) -export const selectAppAction = payload => ({ type: SELECT_APP, payload }) +export const selectAppAction = (payload) => ({ type: SELECT_APP, payload }) -export const savePaymentDetails = ({ apiServer, appId, jwt, btcAddress, stxAddress }) => async dispatch => { +export const savePaymentDetails = ({ apiServer, appId, jwt, btcAddress, stxAddress }) => async (dispatch) => { dispatch(savePaymentDetailsAction()) try { const response = await fetch(`${apiServer}/api/maker/apps?appId=${appId}`, { @@ -54,11 +56,12 @@ export const savePaymentDetails = ({ apiServer, appId, jwt, btcAddress, stxAddre } } -export const fetchApps = ({ user, apiServer }) => async dispatch => { +export const fetchApps = ({ user, apiServer }) => async (dispatch) => { if (!(user && user.jwt)) { dispatch(errorAction()) return } + dispatch(fetchAppsAction()) try { const uri = `${apiServer}/api/maker/apps` @@ -67,8 +70,8 @@ export const fetchApps = ({ user, apiServer }) => async dispatch => { Authorization: `Bearer ${user.jwt}` } }) - const apps = await response.json() - await dispatch(fetchAppsDoneAction(apps)) + const data = await response.json() + await dispatch(fetchAppsDoneAction(data)) } catch (error) { dispatch(fetchAppsFailAction()) } From cf96d7bfc69e28f333994343352934ae513a609e Mon Sep 17 00:00:00 2001 From: Thomas Osmonson Date: Tue, 29 Oct 2019 17:26:47 -0500 Subject: [PATCH 12/19] remove comment --- stores/maker/reducer.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/stores/maker/reducer.js b/stores/maker/reducer.js index 1fdad30a..69145591 100644 --- a/stores/maker/reducer.js +++ b/stores/maker/reducer.js @@ -12,7 +12,6 @@ const initialState = { function makerReducer(state = initialState, action) { switch (action.type) { - case MakerActions.MAKER_AUTH_ERROR: return { ...state, @@ -24,9 +23,8 @@ function makerReducer(state = initialState, action) { return { ...state, loading: false, - appIds: action.payload.apps.map(app => app.id), + appIds: action.payload.apps.map((app) => app.id), appEntities: keyBy(action.payload.apps, 'id') - // selectedAppId: action.payload.apps.length ? action.payload.apps[0].id : null } case MakerActions.SELECT_APP: From f0395010eaf9862c3cb21ae1cac832a884966f08 Mon Sep 17 00:00:00 2001 From: Thomas Osmonson Date: Tue, 29 Oct 2019 17:27:06 -0500 Subject: [PATCH 13/19] add loading selector --- stores/maker/selectors.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/stores/maker/selectors.js b/stores/maker/selectors.js index 82981440..966940f0 100644 --- a/stores/maker/selectors.js +++ b/stores/maker/selectors.js @@ -9,13 +9,15 @@ const updateEntity = (state, id, newProps) => ({ } }) -export const selectMaker = state => state.maker +export const selectMaker = (state) => state.maker -export const selectAppList = state => state.maker.appIds.map(id => state.maker.appEntities[id]) +export const selectIsMakerLoading = (state) => state.maker.loading -export const selectCurrentApp = state => state.maker.appEntities[state.maker.selectedAppId] +export const selectAppList = (state) => state.maker.appIds.map((id) => state.maker.appEntities[id]) -export const selectCompetionStatus = state => { +export const selectCurrentApp = (state) => state.maker.appEntities[state.maker.selectedAppId] + +export const selectCompetionStatus = (state) => { const selectedApp = state.maker.appEntities[state.maker.selectedAppId] if (!selectedApp) { return {} From 77b208b97ed50f87f468187f2028ddb837ddad1f Mon Sep 17 00:00:00 2001 From: Thomas Osmonson Date: Tue, 29 Oct 2019 17:27:56 -0500 Subject: [PATCH 14/19] add document check for ssr --- components/maker/modal.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/components/maker/modal.js b/components/maker/modal.js index 3669d56c..7d944520 100644 --- a/components/maker/modal.js +++ b/components/maker/modal.js @@ -9,7 +9,7 @@ const customStyles = { // above headroom header library zIndex: 100 }, - content : { + content: { top: '50%', left: '50%', right: 'auto', @@ -31,7 +31,7 @@ const CloseButtonContainer = styled.div` const CloseButton = ({ handleClick }) => ( - + ) @@ -40,12 +40,11 @@ const MakerModal = ({ isOpen, handleClose, children }) => ( isOpen={isOpen} onRequestClose={handleClose} style={customStyles} - appElement={document.querySelector('#__next')} + appElement={typeof document !== 'undefined' ? document.querySelector('#__next') : null} > {children} ) - export default MakerModal From bc1d3236599634a953630e50fb1a1879275c8a0a Mon Sep 17 00:00:00 2001 From: Thomas Osmonson Date: Tue, 29 Oct 2019 17:31:00 -0500 Subject: [PATCH 15/19] create jwt cookie when sign in, remove on sign out --- stores/user/index.js | 83 ++++++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 38 deletions(-) diff --git a/stores/user/index.js b/stores/user/index.js index dd1efe05..c85b2db7 100644 --- a/stores/user/index.js +++ b/stores/user/index.js @@ -1,4 +1,5 @@ import { UserSession, AppConfig } from 'blockstack' +import Cookies from 'js-cookie' const host = typeof document === 'undefined' ? 'https://app.co' : document.location.origin const appConfig = new AppConfig(['store_write'], host) @@ -24,35 +25,43 @@ const signingIn = () => ({ const signedIn = (data) => ({ type: constants.SIGNED_IN, - token: data.token, - user: data.user, - userId: data.user.id -}) - -const signOut = () => ({ - type: constants.SIGNING_OUT + payload: { + token: data.token, + user: data.user, + userId: data.user.id + } }) -const handleSignIn = (apiServer) => - async function innerHandleSignIn(dispatch) { - const token = userSession.getAuthResponseToken() - if (!token) { - return true - } - if (userSession.isUserSignedIn()) { - userSession.signUserOut() - } +const signOut = () => { + Cookies.remove('jwt') + return { + type: constants.SIGNING_OUT + } +} - dispatch(signingIn()) - await userSession.handlePendingSignIn() - const url = `${apiServer}/api/authenticate?authToken=${token}` - const response = await fetch(url, { - method: 'POST' - }) - const json = await response.json() - dispatch(signedIn(json)) +const handleSignIn = (apiServer) => async (dispatch) => { + const token = userSession.getAuthResponseToken() + if (!token) { return true } + if (userSession.isUserSignedIn()) { + userSession.signUserOut() + } + + dispatch(signingIn()) + await userSession.handlePendingSignIn() + const url = `${apiServer}/api/authenticate?authToken=${token}` + const response = await fetch(url, { + method: 'POST' + }) + const json = await response.json() + dispatch(signedIn(json)) + const cookie = Cookies.get('jwt') + if (!cookie) { + Cookies.set('jwt', json.token) + } + return true +} const signIn = (redirectPath = 'admin') => { const redirect = `${window.location.origin}/${redirectPath}` @@ -67,25 +76,23 @@ const actions = { signOut } -const reducer = (state = initialState, action) => { - switch (action.type) { +const reducer = (state = initialState, { type, payload }) => { + switch (type) { case constants.SIGNING_IN: - return Object.assign({}, state, { + return { + ...state, signingIn: true - }) + } case constants.SIGNED_IN: - return Object.assign({}, state, { + return { + ...state, signingIn: false, - jwt: action.token, - userId: action.userId, - user: action.user - }) + jwt: payload.token, + userId: payload.userId, + user: payload.user + } case constants.SIGNING_OUT: - return Object.assign({}, state, { - user: null, - userId: null, - jwt: null - }) + return { ...state, user: null, userId: null, jwt: null } default: return state } From 929f5cd68174ea66c06eb69e5623424d41b4c130 Mon Sep 17 00:00:00 2001 From: Thomas Osmonson Date: Tue, 29 Oct 2019 17:31:22 -0500 Subject: [PATCH 16/19] remove console log, prettier --- pages/maker/magic-link.js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/pages/maker/magic-link.js b/pages/maker/magic-link.js index 02563bc1..1b72c72d 100644 --- a/pages/maker/magic-link.js +++ b/pages/maker/magic-link.js @@ -14,6 +14,7 @@ class MakerMagicLink extends React.Component { const { accessToken } = query const apiServer = selectApiServer(reduxStore.getState()) const appResult = await fetch(`${apiServer}/api/magic-link/${accessToken}`) + console.log(appResult) const { app } = await appResult.json() return { @@ -85,7 +86,8 @@ class MakerMagicLink extends React.Component { {app.name} is now owned by {app.adminBlockstackId || user.user.blockstackUsername} - Your Magic Link is now no longer functional. Instead, you will use your Blockstack ID to sign in to the developer portal. + Your Magic Link is now no longer functional. Instead, you will use your Blockstack ID to sign in to + the developer portal. @@ -97,9 +99,12 @@ class MakerMagicLink extends React.Component { Sign in with Blockstack to claim {app.name} - You will use this Blockstack ID to make changes to your app, and remove or modify your listing in the future. + You will use this Blockstack ID to make changes to your app, and remove or modify your listing in + the future. - + )}
@@ -117,4 +122,7 @@ const mapStateToProps = (state) => ({ const mapDispatchToProps = (dispatch) => bindActionCreators({ ...UserStore.actions }, dispatch) -export default connect(mapStateToProps, mapDispatchToProps)(MakerMagicLink) +export default connect( + mapStateToProps, + mapDispatchToProps +)(MakerMagicLink) From 84d346895c497ce177abe32f547d336a57a95a4f Mon Sep 17 00:00:00 2001 From: Thomas Osmonson Date: Tue, 29 Oct 2019 17:31:31 -0500 Subject: [PATCH 17/19] deps --- package.json | 1 + yarn.lock | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/package.json b/package.json index 3cd37d98..37ac0eaa 100644 --- a/package.json +++ b/package.json @@ -64,6 +64,7 @@ "grid-styled": "5.0.2", "intersection-observer": "^0.5.1", "isomorphic-unfetch": "^3.0.0", + "js-cookie": "^2.2.1", "lodash": "^4.17.11", "lodash.debounce": "^4.0.8", "lru-cache": "^4.1.3", diff --git a/yarn.lock b/yarn.lock index b89f41f1..d5ee2cb8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7764,6 +7764,11 @@ jest@^22.4.3: resolved "https://registry.yarnpkg.com/jquery/-/jquery-2.2.4.tgz#2c89d6889b5eac522a7eea32c14521559c6cbf02" integrity sha1-LInWiJterFIqfuoywUUhVZxsvwI= +js-cookie@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8" + integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ== + js-levenshtein@^1.1.3: version "1.1.6" resolved "https://registry.yarnpkg.com/js-levenshtein/-/js-levenshtein-1.1.6.tgz#c6cee58eb3550372df8deb85fad5ce66ce01d59d" From 606b0615cf926ad6c1b7895ff13b937c083a69c8 Mon Sep 17 00:00:00 2001 From: Thomas Osmonson Date: Tue, 29 Oct 2019 17:37:27 -0500 Subject: [PATCH 18/19] refactor maker page to use ssr more effectively --- pages/maker/apps/index.js | 204 ++++++++++++++++++-------------------- 1 file changed, 94 insertions(+), 110 deletions(-) diff --git a/pages/maker/apps/index.js b/pages/maker/apps/index.js index 96edb34c..ae9fc867 100644 --- a/pages/maker/apps/index.js +++ b/pages/maker/apps/index.js @@ -11,131 +11,115 @@ import { MakerContainer, MakerContentBox, MakerStickyStatusBox } from '@componen import { Page } from '@components/page' import Head from '@containers/head' import Maker from '@components/maker' +import { red } from '@atlaskit/theme/dist/cjs/colors' -const MakerPortal = ({ params, apiServer, user, maker, errorMessage, appList, selectedApp, competionStatus, dispatch }) => { +const mapStateToProps = (state) => ({ + user: selectUser(state), + apiServer: selectApiServer(state), + maker: selectMaker(state), + appList: selectAppList(state), + selectedApp: selectCurrentApp(state), + completionStatus: selectCompetionStatus(state) +}) - const hasAppId = params && !!params.appId +const LoadingPage = ({ message = 'Loading...', ...rest }) => ( + + + + + {message} + + + + +) + +const handleChangingApp = (event, fn) => (dispatch) => { + event.persist() + const id = event.target.value + dispatch(selectAppAction(id)) + fn(id) +} - const router = useRouter() +const getAppId = (params) => { + if (!params) return undefined + const id = parseInt(params.appId, 10) + if (isNaN(id)) return undefined + return id +} - const updateMakerRoute = id => router.push( - '/maker/apps', - `/maker/apps/${id}`, - { - shallow: true - } - ) +const MakerPortal = connect()( + ({ maker, selectedApp, appList, appId, apiServer, completionStatus, user, dispatch, ...rest }) => { + const router = useRouter() - const getAppId = () => { - if (!params) return undefined - const id = parseInt(params.appId, 10) - if (isNaN(id)) return undefined - return id - } + const updateMakerRoute = (id) => + router.push('/maker/apps', `/maker/apps/${id}`, { + shallow: true + }) - useEffect(() => { - async function fetchAppsOnInit () { - await fetchApps({ apiServer, user })(dispatch) - if (hasAppId) { - dispatch(selectAppAction(getAppId())) - } - if (!hasAppId && process.browser) { - setTimeout(() => { - console.log(appList) - const { id } = appList[0] - dispatch(selectAppAction(id)) - }) - } - } - fetchAppsOnInit() - }, []) + if (maker.loading || !selectedApp) return - if (maker.loading || !selectedApp) { return ( - - - {maker.loading ? 'Loading...' : errorMessage} + + + + {appList.length && ( + + )} - + + {selectedApp.name} + + + + + + + + + + + + + + + + + + ) } +) - function handleChangingApp (event) { - event.persist() - const id = event.target.value - dispatch(selectAppAction(id)) - updateMakerRoute(id) +MakerPortal.getInitialProps = async ({ req, reduxStore, ...ctx }) => { + const { params, universalCookies } = req + const userCookie = universalCookies.cookies.jwt + const appId = getAppId(params) + const apiServer = selectApiServer(reduxStore.getState()) + await fetchApps({ apiServer, user: { jwt: userCookie } })(reduxStore.dispatch) + let selectedApp = {} + if (appId) { + reduxStore.dispatch(selectAppAction(appId)) + selectedApp = selectCurrentApp(reduxStore.getState()) + } else { + const firstApp = selectAppList(reduxStore.getState())[0] + selectedApp = firstApp } + const props = mapStateToProps(reduxStore.getState()) - return ( - - - - - { - appList.length && - - } - - - {selectedApp.name} - - - - - - - - - - - - - - - - - - - - ) + return { appId, ...props, selectedApp, dispatch: reduxStore.dispatch } } -MakerPortal.getInitialProps = (x) => { - console.log(x.userApps) - return { params: x.query.params } -} - -const mapStateToProps = state => ({ - user: selectUser(state), - apiServer: selectApiServer(state), - maker: selectMaker(state), - appList: selectAppList(state), - selectedApp: selectCurrentApp(state), - competionStatus: selectCompetionStatus(state) -}) - -export default connect(mapStateToProps)(MakerPortal) +export default MakerPortal From f8be5995e28d8fc14d89c536027369446cc124d1 Mon Sep 17 00:00:00 2001 From: Thomas Osmonson Date: Wed, 30 Oct 2019 10:03:44 -0500 Subject: [PATCH 19/19] cleanup --- pages/maker/apps/index.js | 125 +++++++++++++++++++------------------- 1 file changed, 61 insertions(+), 64 deletions(-) diff --git a/pages/maker/apps/index.js b/pages/maker/apps/index.js index ae9fc867..64e30c92 100644 --- a/pages/maker/apps/index.js +++ b/pages/maker/apps/index.js @@ -1,4 +1,4 @@ -import React, { useEffect } from 'react' +import React from 'react' import { useRouter } from 'next/router' import { Flex, Box, Type } from 'blockstack-ui' import { connect } from 'react-redux' @@ -11,7 +11,6 @@ import { MakerContainer, MakerContentBox, MakerStickyStatusBox } from '@componen import { Page } from '@components/page' import Head from '@containers/head' import Maker from '@components/maker' -import { red } from '@atlaskit/theme/dist/cjs/colors' const mapStateToProps = (state) => ({ user: selectUser(state), @@ -22,18 +21,6 @@ const mapStateToProps = (state) => ({ completionStatus: selectCompetionStatus(state) }) -const LoadingPage = ({ message = 'Loading...', ...rest }) => ( - - - - - {message} - - - - -) - const handleChangingApp = (event, fn) => (dispatch) => { event.persist() const id = event.target.value @@ -48,62 +35,72 @@ const getAppId = (params) => { return id } -const MakerPortal = connect()( - ({ maker, selectedApp, appList, appId, apiServer, completionStatus, user, dispatch, ...rest }) => { - const router = useRouter() +const LoadingPage = ({ message = 'Loading...' }) => ( + + + + + {message} + + + + +) + +const MakerPortal = connect()(({ maker, selectedApp, appList, appId, apiServer, completionStatus, user, dispatch }) => { + const router = useRouter() - const updateMakerRoute = (id) => - router.push('/maker/apps', `/maker/apps/${id}`, { - shallow: true - }) + const updateMakerRoute = (id) => + router.push('/maker/apps', `/maker/apps/${id}`, { + shallow: true + }) - if (maker.loading || !selectedApp) return + if (maker.loading || !selectedApp) return - return ( - - - + return ( + + + + + {appList.length && ( + + )} + + + {selectedApp.name} + + + + + - {appList.length && ( - - )} + + + + + + + + + - - {selectedApp.name} - - - - - - - - - - - - - - - - - - - - ) - } -) +
+ + + ) +}) -MakerPortal.getInitialProps = async ({ req, reduxStore, ...ctx }) => { +MakerPortal.getInitialProps = async ({ req, reduxStore }) => { const { params, universalCookies } = req const userCookie = universalCookies.cookies.jwt const appId = getAppId(params)