diff --git a/README.md b/README.md
index d259ae6b714d58c12fe9579adce7bec16cd4a9ad..16f33c35f572e4ec518f7d8851c828fafe0d9f2a 100644
--- a/README.md
+++ b/README.md
@@ -19,9 +19,11 @@ Note: xpub is still _very_ new. This repository contains an initial set of compo
 
 * `xpub-edit`: WYSIWYG editors for use in xpub forms
 * `xpub-fonts`: fonts for use in xpub applications
+* `xpub-journal`: a helper that provides journal config to components
 * `xpub-selectors`: some useful redux selectors
 * `xpub-styleguide`: components for use in react-styleguidist
-* `xpub-ui`: a library of user interface elements for use in PubSweet components.
+* `xpub-ui`: a library of user interface elements for use in PubSweet components
+* `xpub-upload`: a helper function for file uploading
 
 ## Installing
 
diff --git a/packages/component-app/package.json b/packages/component-app/package.json
index 045134755df51665e83dfc9291522262a23d55b5..ffbb61a2ea101d6b5768a52fef6ef59be3590966 100644
--- a/packages/component-app/package.json
+++ b/packages/component-app/package.json
@@ -10,23 +10,18 @@
   ],
   "dependencies": {
     "prop-types": "^15.5.10",
-    "pubsweet-client": "git+https://gitlab.coko.foundation/pubsweet/pubsweet-client.git",
     "react": "^15.6.1",
     "react-dom": "^15.6.1",
-    "react-loadable": "^4.0.3",
     "react-redux": "^5.0.2",
     "react-router": "^3.0.5",
     "react-router-redux": "^4.0.7",
     "recompose": "^0.25.0",
     "redux": "^3.6.0",
-    "redux-form": "^7.0.3",
-    "redux-logger": "^3.0.1",
-    "xpub-selectors": "^0.0.2",
+    "xpub-journal": "^0.0.2",
     "xpub-ui": "^0.0.2"
   },
   "peerDependencies": {
     "prop-types": "^15.5.10",
-    "pubsweet-client": "git+https://gitlab.coko.foundation/pubsweet/pubsweet-client.git",
     "react": "^15.6.1",
     "react-dom": "^15.6.1",
     "react-redux": "^5.0.2",
diff --git a/packages/component-app/src/components/App.js b/packages/component-app/src/components/App.js
index 2b7eeac88b65c8e1cf64835a0487a7a2274749ec..44b8591adb2ae68fc7dc1d609f4b12b424744082 100644
--- a/packages/component-app/src/components/App.js
+++ b/packages/component-app/src/components/App.js
@@ -2,7 +2,7 @@ import React from 'react'
 import { compose } from 'recompose'
 import { connect } from 'react-redux'
 import { AppBar } from 'xpub-ui'
-import { withJournal } from './JournalProvider'
+import { withJournal } from 'xpub-journal'
 import classes from './App.local.scss'
 
 const App = ({ children, currentUser, journal }) => (
diff --git a/packages/component-app/src/components/index.js b/packages/component-app/src/components/index.js
index 95fbdb949c4548b9f439ef6accd0bc3491bd8c78..f52c042e6eb5482ae1d7e5189d7d08a9886e243e 100644
--- a/packages/component-app/src/components/index.js
+++ b/packages/component-app/src/components/index.js
@@ -1,3 +1 @@
 export { default as App } from './App'
-export { JournalProvider, withJournal } from './JournalProvider'
-export { default as ConnectPage } from './ConnectPage'
diff --git a/packages/component-dashboard/package.json b/packages/component-dashboard/package.json
index 6a5fe3e5b7cb64c8cdb4a69b95c865df42f8c0bf..138f1d281376d368724cd95322a79f8ffcc7e209 100644
--- a/packages/component-dashboard/package.json
+++ b/packages/component-dashboard/package.json
@@ -14,7 +14,6 @@
     "prop-types": "^15.5.10",
     "pubsweet-client": "git+https://gitlab.coko.foundation/pubsweet/pubsweet-client.git",
     "pubsweet-component-ink-frontend": "^0.1.0",
-    "pubsweet-component-xpub-app": "^0.0.2",
     "react": "^15.6.1",
     "react-dom": "^15.6.1",
     "react-redux": "^5.0.2",
@@ -22,6 +21,8 @@
     "react-dropzone": "^3.13.3",
     "react-moment": "^0.6.1",
     "recompose": "^0.25.0",
+    "xpub-connect": "^0.0.2",
+    "xpub-journal": "^0.0.2",
     "xpub-selectors": "^0.0.2",
     "xpub-ui": "^0.0.2"
   },
diff --git a/packages/component-dashboard/src/components/AssignEditor.js b/packages/component-dashboard/src/components/AssignEditor.js
index ce2d884b30fff24f2e3b6e613ba4a9153d5dfa93..7012e9460c58d8af59dc0dd9a99dd4e9aa091c0a 100644
--- a/packages/component-dashboard/src/components/AssignEditor.js
+++ b/packages/component-dashboard/src/components/AssignEditor.js
@@ -2,7 +2,7 @@ import React from 'react'
 import { connect } from 'react-redux'
 import { compose } from 'recompose'
 import { Menu } from 'xpub-ui'
-import { withJournal } from 'pubsweet-component-xpub-app/src/components'
+import { withJournal } from 'xpub-journal'
 
 const editorOption = editor => ({
   value: editor.user,
diff --git a/packages/component-dashboard/src/components/DashboardPage.js b/packages/component-dashboard/src/components/DashboardPage.js
index c7f4db500ced410b0264fe16fb3988cdbd83ffa5..f1d7a605bc9af2497d74754d67b8cc5a301d139f 100644
--- a/packages/component-dashboard/src/components/DashboardPage.js
+++ b/packages/component-dashboard/src/components/DashboardPage.js
@@ -3,7 +3,7 @@ import { connect } from 'react-redux'
 import { orderBy } from 'lodash'
 import actions from 'pubsweet-client/src/actions'
 import { selectCurrentUser } from 'xpub-selectors'
-import { ConnectPage } from 'pubsweet-component-xpub-app/src/components'
+import { ConnectPage } from 'xpub-connect'
 import { uploadManuscript } from '../redux/manuscriptConversion'
 import { addUserToTeam } from '../redux/teams'
 import Dashboard from './Dashboard'
diff --git a/packages/component-dashboard/src/components/metadata/MetadataSections.js b/packages/component-dashboard/src/components/metadata/MetadataSections.js
index 3442c2acee10a2727abd42712270f25029941bee..a5a7b32450ea415f134b2f64a4eb4a2c2d816cf5 100644
--- a/packages/component-dashboard/src/components/metadata/MetadataSections.js
+++ b/packages/component-dashboard/src/components/metadata/MetadataSections.js
@@ -1,5 +1,5 @@
 import React from 'react'
-import { withJournal } from 'pubsweet-component-xpub-app/src/components'
+import { withJournal } from 'xpub-journal'
 
 const MetadataSections = ({ journal, sections }) => (
   <span>
diff --git a/packages/component-dashboard/src/components/withVersion.js b/packages/component-dashboard/src/components/withVersion.js
index 2fc4046450e14cf336f817eeb4f87aaa0819cede..bb5d8ba356aac51630b6851f6f09814ccd2a9b99 100644
--- a/packages/component-dashboard/src/components/withVersion.js
+++ b/packages/component-dashboard/src/components/withVersion.js
@@ -1,7 +1,7 @@
 import { compose } from 'recompose'
 import { connect } from 'react-redux'
 import actions from 'pubsweet-client/src/actions'
-import { ConnectPage } from 'pubsweet-component-xpub-app/src/components'
+import { ConnectPage } from 'xpub-connect'
 import { selectFragment } from 'xpub-selectors'
 
 export default Component => (
diff --git a/packages/component-manuscript/package.json b/packages/component-manuscript/package.json
index ce9fc2c8d2eead904ba3733846526b2d9f4f54f1..e08ff83c361a87d198b07bbea311eb706c00096f 100644
--- a/packages/component-manuscript/package.json
+++ b/packages/component-manuscript/package.json
@@ -8,6 +8,7 @@
   "main": "src",
   "dependencies": {
     "pubsweet-component-wax": "^0.1.0",
+    "xpub-connect": "^0.0.2",
     "xpub-selectors": "^0.0.2"
   },
   "peerDependencies": {
@@ -30,7 +31,6 @@
     "faker": "^4.1.0",
     "file-loader": "^0.11.2",
     "node-sass": "^4.5.3",
-    "pubsweet-component-xpub-app": "^0.0.2",
     "recompose": "^0.25.0",
     "rimraf": "^2.6.1",
     "react-styleguidist": "^6.0.8",
diff --git a/packages/component-manuscript/src/components/ManuscriptPage.js b/packages/component-manuscript/src/components/ManuscriptPage.js
index d5fcddc23f0b8a41eecf2ea462e0634b279e8d09..3b02e2eddba514aa905527fad7613a38773585bd 100644
--- a/packages/component-manuscript/src/components/ManuscriptPage.js
+++ b/packages/component-manuscript/src/components/ManuscriptPage.js
@@ -1,7 +1,7 @@
 import { compose } from 'recompose'
 import { connect } from 'react-redux'
 import actions from 'pubsweet-client/src/actions'
-import { ConnectPage } from 'pubsweet-component-xpub-app/src/components'
+import { ConnectPage } from 'xpub-connect'
 import { selectCurrentUser, selectCollection, selectFragment } from 'xpub-selectors'
 import Manuscript from './Manuscript'
 
diff --git a/packages/component-review/package.json b/packages/component-review/package.json
index 0062460cd95e6160093f8746eab4e1937fcee5cc..dee4f66fd0c7c5318d8a99a00cf5d179fce66754 100644
--- a/packages/component-review/package.json
+++ b/packages/component-review/package.json
@@ -14,7 +14,6 @@
     "prop-types": "^15.5.10",
     "pubsweet-client": "git+https://gitlab.coko.foundation/pubsweet/pubsweet-client.git",
     "pubsweet-component-wax": "^0.1.0",
-    "pubsweet-component-xpub-app": "^0.0.2",
     "react": "^15.6.1",
     "react-dom": "^15.6.1",
     "react-redux": "^5.0.2",
@@ -24,9 +23,12 @@
     "redux": "^3.6.0",
     "redux-form": "^7.0.3",
     "striptags": "^3.1.0",
+    "xpub-connect": "^0.0.2",
     "xpub-edit": "^0.0.2",
+    "xpub-journal": "^0.0.2",
     "xpub-selectors": "^0.0.2",
-    "xpub-ui": "^0.0.2"
+    "xpub-ui": "^0.0.2",
+    "xpub-upload": "^0.0.2"
   },
   "devDependencies": {
     "babel-core": "^6.26.0",
diff --git a/packages/component-review/src/components/Decision.js b/packages/component-review/src/components/Decision.js
index 3a3458b3bc558357f2d931ace09c2038b1003116..f9bd6dc45d3784eaf72b6ed4ac0fb1c649c4beb5 100644
--- a/packages/component-review/src/components/Decision.js
+++ b/packages/component-review/src/components/Decision.js
@@ -2,7 +2,7 @@ import React from 'react'
 import { Button } from 'xpub-ui'
 import { NoteEditor } from 'xpub-edit'
 import { RadioGroup, ValidatedField } from 'xpub-ui'
-import { withJournal } from 'pubsweet-component-xpub-app/src/components'
+import { withJournal } from 'xpub-journal'
 import { required } from '../lib/validators'
 import classes from './Decision.local.scss'
 
diff --git a/packages/component-review/src/components/DecisionPage.js b/packages/component-review/src/components/DecisionPage.js
index 5274023cfc9c6c60196e178932d96e1c76ad249b..c9be99523883ee3432274828f272b427aeca3294 100644
--- a/packages/component-review/src/components/DecisionPage.js
+++ b/packages/component-review/src/components/DecisionPage.js
@@ -4,8 +4,8 @@ import { connect } from 'react-redux'
 import { push } from 'react-router-redux'
 import { reduxForm, SubmissionError } from 'redux-form'
 import actions from 'pubsweet-client/src/actions'
-import { ConnectPage } from 'pubsweet-component-xpub-app/src/components'
-import uploadFile from 'pubsweet-component-xpub-app/src/lib/upload'
+import { ConnectPage } from 'xpub-connect'
+import uploadFile from 'xpub-uplod'
 import { selectCollection, selectFragment } from 'xpub-selectors'
 import DecisionLayout from './DecisionLayout'
 
diff --git a/packages/component-review/src/components/Review.js b/packages/component-review/src/components/Review.js
index 07aea88e0741e047699c39e25099b6abc00009aa..fa802d4e21d5601a85630a9186fbd39167c8f42a 100644
--- a/packages/component-review/src/components/Review.js
+++ b/packages/component-review/src/components/Review.js
@@ -2,7 +2,7 @@ import React from 'react'
 import { Button } from 'xpub-ui'
 import { NoteEditor } from 'xpub-edit'
 import { RadioGroup, ValidatedField } from 'xpub-ui'
-import { withJournal } from 'pubsweet-component-xpub-app/src/components'
+import { withJournal } from 'xpub-journal'
 import { required } from '../lib/validators'
 import classes from './Review.local.scss'
 
diff --git a/packages/component-review/src/components/ReviewPage.js b/packages/component-review/src/components/ReviewPage.js
index f6ed4ddc07099a1438bd90803e22c9c4401c7a8c..df548073cb549a9211b6971a8127eb44e4e18e47 100644
--- a/packages/component-review/src/components/ReviewPage.js
+++ b/packages/component-review/src/components/ReviewPage.js
@@ -4,8 +4,8 @@ import { connect } from 'react-redux'
 import { push } from 'react-router-redux'
 import { reduxForm, SubmissionError } from 'redux-form'
 import actions from 'pubsweet-client/src/actions'
-import { ConnectPage } from 'pubsweet-component-xpub-app/src/components'
-import uploadFile from 'pubsweet-component-xpub-app/src/lib/upload'
+import { ConnectPage } from 'xpub-connect'
+import uploadFile from 'xpub-upload'
 import { selectCollection, selectFragment } from 'xpub-selectors'
 import ReviewLayout from './ReviewLayout'
 
diff --git a/packages/component-submit/package.json b/packages/component-submit/package.json
index 3584898d8f0cd3f96028ce84680c0ca9c952525e..cd070469eea97806bfb7fe98140d4d5d5d225092 100644
--- a/packages/component-submit/package.json
+++ b/packages/component-submit/package.json
@@ -13,7 +13,6 @@
     "lodash": "^4.17.4",
     "prop-types": "^15.5.10",
     "pubsweet-client": "git+https://gitlab.coko.foundation/pubsweet/pubsweet-client.git",
-    "pubsweet-component-xpub-app": "^0.0.2",
     "react": "^15.6.1",
     "react-dom": "^15.6.1",
     "react-redux": "^5.0.2",
@@ -23,9 +22,12 @@
     "redux": "^3.6.0",
     "redux-form": "^7.0.3",
     "striptags": "^3.1.0",
+    "xpub-connect": "^0.0.2",
     "xpub-edit": "^0.0.2",
+    "xpub-journal": "^0.0.2",
     "xpub-selectors": "^0.0.2",
-    "xpub-ui": "^0.0.2"
+    "xpub-ui": "^0.0.2",
+    "xpub-upload": "^0.0.2"
   },
   "devDependencies": {
     "babel-core": "^6.26.0",
diff --git a/packages/component-submit/src/components/Declarations.js b/packages/component-submit/src/components/Declarations.js
index d88b863c898e7c92c10001b08634d1d3d7b038e7..3f9ae7c487d7fdbc914fba7534f4d5615226cd21 100644
--- a/packages/component-submit/src/components/Declarations.js
+++ b/packages/component-submit/src/components/Declarations.js
@@ -2,7 +2,7 @@ import React from 'react'
 import classnames from 'classnames'
 import { FormSection } from 'redux-form'
 import { ValidatedField, YesOrNo } from 'xpub-ui'
-import { withJournal } from 'pubsweet-component-xpub-app/src/components'
+import { withJournal } from 'xpub-journal'
 import { required } from '../lib/validators'
 import classes from './Declarations.local.scss'
 
diff --git a/packages/component-submit/src/components/Metadata.js b/packages/component-submit/src/components/Metadata.js
index 593ac829c98bfe4bb7e9a2094042e3d4f7734267..5221fc166fae2ca0740c09872a8054d55ffea287 100644
--- a/packages/component-submit/src/components/Metadata.js
+++ b/packages/component-submit/src/components/Metadata.js
@@ -2,7 +2,7 @@ import React from 'react'
 import { FormSection } from 'redux-form'
 import { AbstractEditor, TitleEditor } from 'xpub-edit'
 import { CheckboxGroup, Menu, TextField, ValidatedField } from 'xpub-ui'
-import { withJournal } from 'pubsweet-component-xpub-app/src/components'
+import { withJournal } from 'xpub-journal'
 import classes from './Metadata.local.scss'
 import { join, required, minChars, maxChars, minSize, split } from '../lib/validators'
 
diff --git a/packages/component-submit/src/components/SubmitPage.js b/packages/component-submit/src/components/SubmitPage.js
index c580e6e1ebe74c6c34e16cc63466a162b694ac5e..c10380a8c8bcad43e7f5162dcdb35c806d6b4ed5 100644
--- a/packages/component-submit/src/components/SubmitPage.js
+++ b/packages/component-submit/src/components/SubmitPage.js
@@ -4,8 +4,8 @@ import { connect } from 'react-redux'
 import { push } from 'react-router-redux'
 import { reduxForm, SubmissionError } from 'redux-form'
 import actions from 'pubsweet-client/src/actions'
-import uploadFile from 'pubsweet-component-xpub-app/src/lib/upload'
-import { ConnectPage } from 'pubsweet-component-xpub-app/src/components'
+import uploadFile from 'xpub-upload'
+import { ConnectPage } from 'xpub-connect'
 import { selectCollection, selectFragment } from 'xpub-selectors'
 import Submit from './Submit'
 
diff --git a/packages/xpub-collabra/app/Root.js b/packages/xpub-collabra/app/Root.js
index 7743eb7245028cdae2d13eeaaa49223b4f904c92..cb05fdaa2a1c56adbc5f0c1352f17e3ebc558827 100644
--- a/packages/xpub-collabra/app/Root.js
+++ b/packages/xpub-collabra/app/Root.js
@@ -3,7 +3,7 @@ import { Provider as StoreProvider } from 'react-redux'
 import { Router, browserHistory } from 'react-router'
 import { syncHistoryWithStore } from 'react-router-redux'
 import { configureStore } from 'pubsweet-client'
-import { JournalProvider } from 'pubsweet-component-xpub-app/src/components'
+import { JournalProvider } from 'xpub-journal'
 
 const store = configureStore(browserHistory, {})
 const history = syncHistoryWithStore(browserHistory, store)
diff --git a/packages/xpub-connect/package.json b/packages/xpub-connect/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..f106ae5ff7960a609c95c4d506e9b913fef3984a
--- /dev/null
+++ b/packages/xpub-connect/package.json
@@ -0,0 +1,28 @@
+{
+  "name": "xpub-connect",
+  "version": "0.0.2",
+  "main": "src",
+  "author": "Collaborative Knowledge Foundation",
+  "license": "MIT",
+  "files": [
+    "src",
+    "dist"
+  ],
+  "dependencies": {
+    "react": "^15.6.1",
+    "react-dom": "^15.6.1",
+    "react-redux": "^5.0.2",
+    "react-router": "^3.0.5",
+    "react-router-redux": "^4.0.7",
+    "recompose": "^0.25.0",
+    "redux": "^3.6.0"
+  },
+  "peerDependencies": {
+    "react": "^15.6.1",
+    "react-dom": "^15.6.1",
+    "react-redux": "^5.0.2",
+    "react-router": "^3.0.5",
+    "react-router-redux": "^4.0.7",
+    "redux": "^3.6.0"
+  }
+}
diff --git a/packages/component-app/src/components/ConnectPage.js b/packages/xpub-connect/src/components/ConnectPage.js
similarity index 100%
rename from packages/component-app/src/components/ConnectPage.js
rename to packages/xpub-connect/src/components/ConnectPage.js
diff --git a/packages/component-app/src/components/ConnectPage.local.scss b/packages/xpub-connect/src/components/ConnectPage.local.scss
similarity index 100%
rename from packages/component-app/src/components/ConnectPage.local.scss
rename to packages/xpub-connect/src/components/ConnectPage.local.scss
diff --git a/packages/xpub-connect/src/components/index.js b/packages/xpub-connect/src/components/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..bbadf19f65c04dd24f9db441d591fb850a75e9ce
--- /dev/null
+++ b/packages/xpub-connect/src/components/index.js
@@ -0,0 +1 @@
+export { default as ConnectPage } from './ConnectPage'
diff --git a/packages/xpub-connect/src/index.js b/packages/xpub-connect/src/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..cb64ac1b52aada9efed12f125d46e795166c96ad
--- /dev/null
+++ b/packages/xpub-connect/src/index.js
@@ -0,0 +1 @@
+export * from './components'
diff --git a/packages/xpub-journal/package.json b/packages/xpub-journal/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..57075f32a9a5b06b1a7217a411bf45b8deb8731b
--- /dev/null
+++ b/packages/xpub-journal/package.json
@@ -0,0 +1,22 @@
+{
+  "name": "xpub-journal",
+  "version": "0.0.2",
+  "main": "src",
+  "author": "Collaborative Knowledge Foundation",
+  "license": "MIT",
+  "files": [
+    "src",
+    "dist"
+  ],
+  "dependencies": {
+    "prop-types": "^15.5.10",
+    "react": "^15.6.1",
+    "react-dom": "^15.6.1",
+    "recompose": "^0.25.0"
+  },
+  "peerDependencies": {
+    "prop-types": "^15.5.10",
+    "react": "^15.6.1",
+    "react-dom": "^15.6.1"
+  }
+}
diff --git a/packages/component-app/src/components/JournalProvider.js b/packages/xpub-journal/src/components/JournalProvider.js
similarity index 100%
rename from packages/component-app/src/components/JournalProvider.js
rename to packages/xpub-journal/src/components/JournalProvider.js
diff --git a/packages/xpub-journal/src/components/index.js b/packages/xpub-journal/src/components/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..2a193d6a18395e6f912765a66bc316d8c297e8c8
--- /dev/null
+++ b/packages/xpub-journal/src/components/index.js
@@ -0,0 +1 @@
+export { JournalProvider, withJournal } from './JournalProvider'
diff --git a/packages/xpub-journal/src/index.js b/packages/xpub-journal/src/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..cb64ac1b52aada9efed12f125d46e795166c96ad
--- /dev/null
+++ b/packages/xpub-journal/src/index.js
@@ -0,0 +1 @@
+export * from './components'
diff --git a/packages/xpub-styleguide/package.json b/packages/xpub-styleguide/package.json
index cb8c33d2b9b6911e8e099c97fd3c27e4092b17ee..9901e4cbcaa0aa902afc4638b635680bbffc9e7d 100644
--- a/packages/xpub-styleguide/package.json
+++ b/packages/xpub-styleguide/package.json
@@ -13,7 +13,6 @@
     "react-redux": "^5.0.2",
     "redux": "^3.6.0",
     "redux-form": "^7.0.3",
-    "pubsweet-component-xpub-app": "^0.0.2"
   },
   "devDependencies": {
     "babel-core": "^6.26.0",
diff --git a/packages/xpub-styleguide/src/components/Wrapper.js b/packages/xpub-styleguide/src/components/Wrapper.js
index ce6c4554c6fe17b31a27ed132b82e8d8251d24fb..0df3c25ed37dbb3c6e9db5b9d41e96829bf78ae0 100644
--- a/packages/xpub-styleguide/src/components/Wrapper.js
+++ b/packages/xpub-styleguide/src/components/Wrapper.js
@@ -2,7 +2,7 @@ import React from 'react'
 import { Provider } from 'react-redux'
 import { reducer as formReducer } from 'redux-form'
 import { createStore, combineReducers } from 'redux'
-import { JournalProvider } from 'pubsweet-component-xpub-app/src/components'
+import { JournalProvider } from 'xpub-journal'
 import * as journal from '../config/journal'
 
 import 'xpub-fonts'
diff --git a/packages/xpub-upload/package.json b/packages/xpub-upload/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..39d8b218f91190acf0414f3769b27a28737a8cd9
--- /dev/null
+++ b/packages/xpub-upload/package.json
@@ -0,0 +1,29 @@
+{
+  "name": "xpub-upload",
+  "version": "0.0.2",
+  "main": "src",
+  "author": "Collaborative Knowledge Foundation",
+  "license": "MIT",
+  "files": [
+    "src",
+    "dist"
+  ],
+  "dependencies": {
+    "pubsweet-client": "git+https://gitlab.coko.foundation/pubsweet/pubsweet-client.git",
+    "react": "^15.6.1",
+    "react-dom": "^15.6.1",
+    "react-redux": "^5.0.2",
+    "react-router": "^3.0.5",
+    "react-router-redux": "^4.0.7",
+    "recompose": "^0.25.0",
+    "redux": "^3.6.0"
+  },
+  "peerDependencies": {
+    "react": "^15.6.1",
+    "react-dom": "^15.6.1",
+    "react-redux": "^5.0.2",
+    "react-router": "^3.0.5",
+    "react-router-redux": "^4.0.7",
+    "redux": "^3.6.0"
+  }
+}
diff --git a/packages/xpub-upload/src/components/ConnectPage.js b/packages/xpub-upload/src/components/ConnectPage.js
new file mode 100644
index 0000000000000000000000000000000000000000..fbfb91e635d686d9cf56e62aadcbdf91c55a5743
--- /dev/null
+++ b/packages/xpub-upload/src/components/ConnectPage.js
@@ -0,0 +1,80 @@
+import React from 'react'
+import { compose } from 'recompose'
+import { connect } from 'react-redux'
+import { withRouter } from 'react-router'
+import classes from './ConnectPage.local.scss'
+
+const ConnectPage = requirements => WrappedComponent => {
+  class ConnectedComponent extends React.Component {
+    state = {
+      fetching: false,
+      complete: false,
+      error: null
+    }
+
+    componentDidMount () {
+      this.fetch(this.props)
+    }
+
+    componentWillReceiveProps (nextProps) {
+      this.fetch(nextProps)
+    }
+
+    fetch ({ isAuthenticated }) {
+      if (!isAuthenticated) {
+        return
+      }
+
+      if (this.state.fetching) {
+        return
+      }
+
+      this.setState({
+        fetching: true,
+        complete: false
+      })
+
+      const requests = requirements(this.props).map(this.props.dispatch)
+
+      Promise.all(requests).then(() => {
+        this.setState({
+          fetching: false,
+          complete: true,
+        })
+      }).catch(error => {
+        console.error(error)
+
+        this.setState({
+          error: error.message
+        })
+
+        throw error // rethrow
+      })
+    }
+
+    render () {
+      const { complete, error } = this.state
+
+      if (error) return (
+        <div className={classes.error}>{error}</div>
+      )
+
+      if (!complete) return (
+        <div className={classes.bar}>loading…</div>
+      )
+
+      return <WrappedComponent {...this.props}/>
+    }
+  }
+
+  return compose(
+    connect(
+      state => ({
+        isAuthenticated: state.currentUser.isAuthenticated
+      })
+    ),
+    withRouter
+  )(ConnectedComponent)
+}
+
+export default ConnectPage
diff --git a/packages/xpub-upload/src/components/ConnectPage.local.scss b/packages/xpub-upload/src/components/ConnectPage.local.scss
new file mode 100644
index 0000000000000000000000000000000000000000..0b857f692d01d118ba6c4ba0d94ef611d218ca50
--- /dev/null
+++ b/packages/xpub-upload/src/components/ConnectPage.local.scss
@@ -0,0 +1,8 @@
+.bar {
+  display: flex;
+  justify-content: center;
+}
+
+.error {
+  color: red;
+}
diff --git a/packages/xpub-upload/src/components/index.js b/packages/xpub-upload/src/components/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..bbadf19f65c04dd24f9db441d591fb850a75e9ce
--- /dev/null
+++ b/packages/xpub-upload/src/components/index.js
@@ -0,0 +1 @@
+export { default as ConnectPage } from './ConnectPage'
diff --git a/packages/component-app/src/lib/upload.js b/packages/xpub-upload/src/index.js
similarity index 100%
rename from packages/component-app/src/lib/upload.js
rename to packages/xpub-upload/src/index.js