diff --git a/src/components/LayersEditor.vue b/src/components/LayersEditor.vue
index 3d4d3ee6821c1037c9e03a2a4dc26697d497e026..c3b86daa8d24674dafd054bd8fd48c49950e5be4 100644
--- a/src/components/LayersEditor.vue
+++ b/src/components/LayersEditor.vue
@@ -15,13 +15,13 @@
       <b-input :placeholder="'Layer ' + index + ' name'" v-model="layer.name"/>
 
       <p class="control">
-        <b-upload v-model="file" accept=".py">
+        <b-upload v-model="layer.file" accept=".py">
           <a class="button is-primary">
             <b-icon icon="upload"></b-icon>
             <span>Upload layer file</span>
           </a>
         </b-upload>
-        <span class="file-name" v-if="file">{{ file.name }}</span>
+        <span class="file-name" v-if="layer.file">{{ layer.file.name }}</span>
       </p>
 
     </b-field>
diff --git a/src/components/LoginForm.vue b/src/components/LoginForm.vue
index 44afa98208fb4d1b7ecd9ff64c61f00c33fcb952..8c9093325dc76ac32690a1a85a1e6498712d7252 100644
--- a/src/components/LoginForm.vue
+++ b/src/components/LoginForm.vue
@@ -5,6 +5,8 @@
         <p class="modal-card-title">Login</p>
       </header>
       <section class="modal-card-body">
+        <h2 class="subtitle has-text-danger">{{errorMessage}}</h2>
+
         <b-field label="Email">
           <b-input type="email" v-model="email" placeholder="email" required/>
         </b-field>
@@ -29,7 +31,8 @@ export default {
   data () {
     return {
       email: '',
-      password: ''
+      password: '',
+      errorMessage: null
     }
   },
   methods: {
@@ -40,7 +43,7 @@ export default {
         this.$parent.close()
         this.$router.go()
       } else {
-        this.$buefy.toast.open('Email ou mot de passe incorect')
+        this.errorMessage = 'Email or password incorect'
       }
     },
     async login (email, password) {
diff --git a/src/components/ModelUpload.vue b/src/components/ModelUpload.vue
new file mode 100644
index 0000000000000000000000000000000000000000..f5e52b64caf1d90649d74de5a17d3770d80d62cf
--- /dev/null
+++ b/src/components/ModelUpload.vue
@@ -0,0 +1,166 @@
+<template>
+  <div class="modal-card">
+    <b-progress :value="progress" size="is-large" show-value :type="status">
+      {{message}}
+    </b-progress>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'ModelUpload',
+  props: {
+    model: {
+      type: Object,
+      default: function () {
+        return {}
+      }
+    }
+  },
+  data () {
+    return {
+      message: '',
+      progress: 0,
+      status: 'is-primary',
+      stausMessage: '',
+      modelId: null
+    }
+  },
+  mounted () {
+    this.saveModel()
+  },
+  methods: {
+    setProgress (step) {
+      switch (step) {
+        case 0:
+          this.message = 'Sending description'
+          this.progress = 25
+          break
+        case 1:
+          this.message = 'Sending model file'
+          this.progress = 50
+          break
+        case 2:
+          this.message = 'Sending custom layers model'
+          this.progress = 75
+          break
+        case 3:
+          this.message = 'Upload completed !'
+          this.progress = 100
+          this.status = 'is-success'
+          break
+      }
+    },
+    setError (message) {
+      this.message = message
+      this.status = 'is-danger'
+    },
+    async saveModel () {
+      this.setProgress(0)
+      var response = await this.uploadModel()
+      if (response.error) {
+        this.setError(response.message)
+        return
+      } else {
+        this.modelId = response.id
+      }
+
+      if (this.model.file !== undefined) {
+        console.log('Upload model ' + this.model.file)
+        this.setProgress(1)
+        if (!await this.uploadModelFile()) {
+          this.setError('Model upload error')
+          return
+        }
+      }
+
+      if (this.model.customLayers !== undefined) {
+        console.log('Upload layers ' + this.model.customLayers)
+        this.setProgress(2)
+        if (!await this.uploadLayers()) {
+          this.setError('Custom layer upload error')
+          return
+        }
+      }
+
+      this.setProgress(3)
+    },
+    async uploadModel () {
+      const url = this.$serverurl + 'models'
+      const token = await localStorage.getItem('token')
+      try {
+        const response = await fetch(url, {
+          method: 'POST',
+          headers: {
+            Accept: 'application/json',
+            'Content-Type': 'application/json',
+            Authorization: 'Bearer ' + token
+          },
+          body: JSON.stringify({
+            name: this.model.name,
+            shortDescription: this.model.shortDescription,
+            longDescription: this.model.longDescription,
+            performance: this.model.performance,
+            tags: this.model.tags,
+            customLayers: this.model.customLayers
+          })
+        })
+        return await response.json()
+      } catch (error) {
+        return null
+      }
+    },
+    async uploadModelFile () {
+      const data = new FormData()
+      const url = this.$serverurl + 'models?id=' + this.modelId + '/upload'
+      const token = await localStorage.getItem('token')
+
+      data.append('model', this.model.file)
+
+      try {
+        const response = await fetch(url, {
+          method: 'POST',
+          headers: {
+            Authorization: 'Bearer ' + token
+          },
+          body: data
+        })
+        return response !== 200
+      } catch (error) {
+        return null
+      }
+    },
+    async uploadLayers () {
+      const token = await localStorage.getItem('token')
+      for (var i = 0; i < this.model.customLayers.length; i++) {
+        const layer = this.model.customLayers[i]
+        const data = new FormData()
+        const url = this.$serverurl + 'models?id=' + this.modelId + '/layer?id=' + i
+
+        console.log('Upload layers ' + i + ' | ' + layer.file)
+        if (layer.file === undefined) continue
+
+        data.append('layer', layer.file)
+
+        try {
+          const response = await fetch(url, {
+            method: 'POST',
+            headers: {
+              Authorization: 'Bearer ' + token
+            },
+            body: data
+          })
+          if (response !== 200) return false
+        } catch (error) {
+          return false
+        }
+      }
+      return true
+    }
+  }
+}
+</script>
+
+<style>
+
+</style>
diff --git a/src/components/RegisterForm.vue b/src/components/RegisterForm.vue
index 7151ed2780f8568f5230a81c61952edc62b7089b..ddf95544b790aec1898724dd3abcbe87d86f4195 100644
--- a/src/components/RegisterForm.vue
+++ b/src/components/RegisterForm.vue
@@ -5,25 +5,26 @@
         <p class="modal-card-title">Sign up</p>
       </header>
       <section class="modal-card-body">
+        <h2 class="subtitle has-text-danger">{{errorMessage}}</h2>
         <b-field label="Email">
-          <b-input type="email" v-model="email" placeholder="email" required/>
+          <b-input type="email" v-model="email" placeholder="email" required maxlength="50"/>
         </b-field>
 
         <b-field label="Username">
-          <b-input v-model="username" placeholder="username" required/>
+          <b-input v-model="username" placeholder="username" required maxlength="30"/>
         </b-field>
 
         <b-field label="Password">
-          <b-input type="password" v-model="password" password-reveal placeholder="password" required/>
+          <b-input type="password" v-model="password" password-reveal placeholder="password" required maxlength="50"/>
         </b-field>
 
         <b-field label="Confirm password">
-          <b-input type="password" v-model="passwordConfirm" password-reveal placeholder="password" required/>
+          <b-input type="password" v-model="passwordConfirm" password-reveal placeholder="password" required maxlength="50"/>
         </b-field>
 
       </section>
       <footer class="modal-card-foot">
-        <button class="button is-primary">Make account</button>
+        <button class="button is-primary" @click="onRegister">Make account</button>
       </footer>
     </div>
   </form>
@@ -37,7 +38,46 @@ export default {
       email: '',
       username: '',
       password: '',
-      passwordConfirm: ''
+      passwordConfirm: '',
+      errorMessage: null
+    }
+  },
+  methods: {
+    async onRegister () {
+      if (this.password !== this.passwordConfirm) {
+        this.errorMessage = 'Passwords are different'
+        return
+      }
+      const response = await this.register(this.username, this.email, this.password)
+      if (response.error) {
+        this.errorMessage = response.message
+      } else {
+        await localStorage.setItem('token', response.token)
+        this.$parent.close()
+        this.$router.go()
+      }
+    },
+    async register (username, email, password) {
+      const url = this.$serverurl + 'user'
+      try {
+        const response = await fetch(
+          url, {
+            method: 'POST',
+            headers: {
+              Accept: 'application/json',
+              'Content-Type': 'application/json'
+            },
+            body: JSON.stringify({
+              email: email,
+              username: username,
+              password: password
+            })
+          }
+        )
+        return await response.json()
+      } catch (error) {
+        return null
+      }
     }
   }
 }
diff --git a/src/router/index.js b/src/router/index.js
index 0792ffa14302734c1b0328c90c9a4050c69d9296..0e97d71d61db92392316d137351afac962c9353f 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -25,6 +25,11 @@ const routes = [
     name: 'Search',
     component: () => import('../views/Search.vue')
   },
+  {
+    path: '/useredit',
+    name: 'UserEdit',
+    component: () => import('../views/UserEdit.vue')
+  },
   {
     path: '/model',
     name: 'Model',
diff --git a/src/views/About.vue b/src/views/About.vue
index 77a63abeed1e4db788f5cfa52612d6ca92c57020..8a780a32c24e863a45a3a5ed8fca293fed33f85e 100644
--- a/src/views/About.vue
+++ b/src/views/About.vue
@@ -1,5 +1,5 @@
 <template>
-  <div class="about">
+  <div class="about container">
     <h1>About page</h1>
   </div>
 </template>
diff --git a/src/views/Account.vue b/src/views/Account.vue
index 925ec119fb30f3dbe3c425a9f9ab05b81e895634..dd88602c61d38ad968de53bb7dd1a4881d198d01 100644
--- a/src/views/Account.vue
+++ b/src/views/Account.vue
@@ -3,8 +3,22 @@
     <div class="box">
       <h1 class="title">Welcome {{account.username}}</h1>
       <div class="buttons">
-        <b-button tag="router-link" :to="{ name: 'ModelAdd' }">Add new model</b-button>
-        <b-button>Change account details</b-button>
+        <b-button
+         icon-left="plus"
+         type="is-info"
+         tag="router-link"
+         :to="{ name: 'ModelAdd' }"
+        >
+        Add new model
+        </b-button>
+        <b-button
+         icon-left="pencil"
+         type="is-info"
+         tag="router-link"
+         :to="{ name: 'UserEdit' }"
+        >
+        Change account details
+        </b-button>
       </div>
     </div>
     <div class="box">
@@ -46,5 +60,7 @@ export default {
 </script>
 
 <style scoped>
-
+.account{
+  margin-top: 20px;
+}
 </style>
diff --git a/src/views/Docs.vue b/src/views/Docs.vue
index 609fdb4691da7d3d4c0fa74d64907c75c73f91ba..6a2b47da2ba6241e0dc21f2975f200827db67c50 100644
--- a/src/views/Docs.vue
+++ b/src/views/Docs.vue
@@ -1,5 +1,5 @@
 <template>
-  <div class="docs">
+  <div class="docs container">
     <h1>Documentation page</h1>
   </div>
 </template>
diff --git a/src/views/Model.vue b/src/views/Model.vue
index 440874f39b7813f8ad7c40d80fe5d4e45818af87..17e0c51e448282799d9e0ad77c966d7a4380b7b7 100644
--- a/src/views/Model.vue
+++ b/src/views/Model.vue
@@ -38,7 +38,14 @@
         </div>
       </div>
       <div class="box">
-        <div class="content" v-html="compiledLongDescription"></div>
+        <b-tabs>
+          <b-tab-item label="Read me">
+            <div class="content" v-html="compiledLongDescription"></div>
+          </b-tab-item>
+
+          <b-tab-item label="Layers">
+          </b-tab-item>
+        </b-tabs>
       </div>
       <div class="box">
         <Comments v-bind:comments="model.comments"/>
diff --git a/src/views/ModelAdd.vue b/src/views/ModelAdd.vue
index 51c35027a6083eeb48ad03ecac697d1cf9912e2d..46f7b29606042debd091c7c42fe85bf4728d544b 100644
--- a/src/views/ModelAdd.vue
+++ b/src/views/ModelAdd.vue
@@ -3,25 +3,25 @@
     <b-steps v-model="activeStep">
       <b-step-item step="1" label="Description" clickable>
         <b-field label="Model name">
-          <b-input maxlength="30" size="is-large"/>
+          <b-input maxlength="30" size="is-large" v-model="model.name"/>
         </b-field>
 
         <b-field label="Short description">
-          <b-input maxlength="200" type="textarea"/>
+          <b-input maxlength="200" type="textarea" v-model="model.shortDescription"/>
         </b-field>
 
         <b-field label="Long description">
-          <markdownEditor/>
+          <markdownEditor v-bind:input="model.longDescription"/>
         </b-field>
       </b-step-item>
 
       <b-step-item step="2" label="Tags" clickable>
-        <tagEditor/>
+        <tagEditor v-bind:tags="model.tags"/>
       </b-step-item>
 
       <b-step-item step="3" label="Files" clickable>
         <b-field label="Model">
-          <b-upload v-model="dropFiles" drag-drop expanded>
+          <b-upload v-model="model.file" drag-drop expanded>
             <section class="section">
               <div class="content has-text-centered">
                 <p>
@@ -35,14 +35,18 @@
       </b-step-item>
 
       <b-step-item step="4" label="Custom layers" clickable>
-        <layersEditor/>
+        <layersEditor v-bind:layers="model.customLayers"/>
       </b-step-item>
 
       <b-step-item step="5" label="Finish" clickable>
-        <b-button expanded size="is-large" type="is-success">Confirm and upload</b-button>
+        <b-button expanded size="is-large" type="is-success" @click="openUploadModal">Confirm and upload</b-button>
       </b-step-item>
 
     </b-steps>
+
+    <b-modal :active.sync="isUploadModalActive" has-modal-card trap-focus aria-role="dialog" aria-modal>
+      <ModelUpload v-bind:model="model"/>
+    </b-modal>
   </div>
 </template>
 
@@ -50,17 +54,26 @@
 import markdownEditor from '@/components/MarkdownEditor.vue'
 import tagEditor from '@/components/TagEditor.vue'
 import layersEditor from '@/components/LayersEditor.vue'
+import ModelUpload from '@/components/ModelUpload.vue'
 
 export default {
   name: 'ModelAdd',
   components: {
     markdownEditor,
     tagEditor,
-    layersEditor
+    layersEditor,
+    ModelUpload
   },
   data () {
     return {
-      activeStep: 0
+      model: {},
+      activeStep: 0,
+      isUploadModalActive: false
+    }
+  },
+  methods: {
+    openUploadModal () {
+      this.isUploadModalActive = true
     }
   }
 }
diff --git a/src/views/ModelEdit.vue b/src/views/ModelEdit.vue
index 69f30ac20d554e2cc0d2b3bbaa830f6b0d23800f..d088c265c0990f1e798826cda221bf8821e6af29 100644
--- a/src/views/ModelEdit.vue
+++ b/src/views/ModelEdit.vue
@@ -25,7 +25,7 @@
       <div class="columns">
         <div class="column">
           <b-field label="Model">
-            <b-upload v-model="dropFiles" drag-drop expanded>
+            <b-upload v-model="model.file" drag-drop expanded>
               <section class="section">
                 <div class="content has-text-centered">
                   <p>
@@ -45,9 +45,13 @@
 
     </div>
     <div class="box">
-      <b-button >Cancel</b-button>
-      <b-button type="is-success">Save</b-button>
+      <b-button tag="router-link" :to="{ name: 'Account' }">Cancel</b-button>
+      <b-button type="is-success" @click="openUploadModal">Save</b-button>
     </div>
+
+    <b-modal :active.sync="isUploadModalActive" has-modal-card trap-focus aria-role="dialog" aria-modal>
+      <ModelUpload v-bind:model="model"/>
+    </b-modal>
   </div>
 </template>
 
@@ -55,13 +59,15 @@
 import markdownEditor from '@/components/MarkdownEditor.vue'
 import tagEditor from '@/components/TagEditor.vue'
 import layersEditor from '@/components/LayersEditor.vue'
+import ModelUpload from '@/components/ModelUpload.vue'
 
 export default {
   name: 'ModelEdit',
   components: {
     markdownEditor,
     tagEditor,
-    layersEditor
+    layersEditor,
+    ModelUpload
   },
   props: {
     model: {
@@ -71,15 +77,23 @@ export default {
       }
     }
   },
+  data () {
+    return {
+      isUploadModalActive: false
+    }
+  },
   methods: {
-    async saveModel () {
-
+    openUploadModal () {
+      this.isUploadModalActive = true
     }
   }
 }
 </script>
 
 <style scoped>
+.modelEdit{
+  margin-top: 20px;
+}
 .rightColumn {
   border-left: 2px solid whitesmoke;
 }
diff --git a/src/views/UserEdit.vue b/src/views/UserEdit.vue
new file mode 100644
index 0000000000000000000000000000000000000000..65f1cf6197b7b759f3538c93a60bd33e53f291a8
--- /dev/null
+++ b/src/views/UserEdit.vue
@@ -0,0 +1,40 @@
+<template>
+  <div class="userEdit container">
+    <h1 class="title">Account details</h1>
+
+    <b-field label="Email">
+      <b-input v-model="user.email" type="email"  maxlength="50"/>
+    </b-field>
+
+    <b-field label="Username">
+      <b-input v-model="user.username" maxlength="30"/>
+    </b-field>
+
+    <b-field label="Password">
+      <b-input type="password" v-model="user.password" password-reveal maxlength="50"/>
+    </b-field>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'UserEdit',
+  props: {
+    user: {
+      type: Object,
+      default: function () {
+        return {}
+      }
+    }
+  },
+  methods: {
+    saveUser () {
+
+    }
+  }
+}
+</script>
+
+<style>
+
+</style>