Browse Source

vuex-orm poc init

Vincent GUFFON 5 years ago
parent
commit
c163521422

+ 15 - 0
.eslintrc.js

@@ -0,0 +1,15 @@
+module.exports = {
+  root: true,
+  env: {
+    browser: true,
+    node: true
+  },
+  extends: [
+    '@nuxtjs/eslint-config-typescript',
+    'plugin:nuxt/recommended'
+  ],
+  plugins: [
+  ],
+  // add your custom rules here
+  rules: {}
+}

+ 27 - 0
components/AlertComponent.vue

@@ -0,0 +1,27 @@
+<template>
+  <v-alert :type="type" class="position">
+    <slot></slot>
+  </v-alert>
+</template>
+
+<script lang="ts">
+  import {defineComponent, ref} from "@vue/composition-api";
+
+  export default defineComponent({
+    props: {
+      type:{
+        type: String,
+        required: true
+      }
+    }
+  })
+</script>
+
+<style scoped>
+  .position{
+    position: fixed;
+    width: 300px;
+    bottom: 0;
+    right: 0;
+  }
+</style>

+ 59 - 0
components/DataTableComponent.vue

@@ -0,0 +1,59 @@
+<template>
+  <v-col
+    cols="12"
+    sm="12"
+  >
+    <v-data-table
+      :headers="headers"
+      :items="entries"
+      :options.sync="options"
+      :server-items-length="totalEntries"
+      :loading="loading"
+      class="elevation-1"
+    ></v-data-table>
+  </v-col>
+</template>
+
+<script lang="ts">
+  import {defineComponent, ref} from '@vue/composition-api'
+  import {Repository} from "@vuex-orm/core";
+  import personActivitiesData from '@/data/personActivitiesData'
+
+  export default defineComponent({
+    props: {
+      repository:{
+        type: Object as () => Repository,
+        required: true
+      },
+      uri:{
+        type: String,
+        required: true
+      },
+      headers:{
+        type: Array,
+        required: true
+      }
+    },
+    setup() {
+      const totalEntries = ref(0)
+      const entries = ref([])
+      const loading = ref(true)
+      const options = ref({})
+
+      return {
+        entries,
+        totalEntries,
+        loading,
+        options
+      }
+    },
+    async fetch() {
+     // const entries = await this.$http.$get(`https://local.new.api.opentalent.fr/api/${this.uri}`)
+      const entries = await personActivitiesData()
+      this.repository.insert(entries['hydra:member']);
+      this.entries = this.repository.all()
+      this.totalEntries = entries['hydra:totalItems']
+      this.loading = false
+    }
+  })
+</script>

+ 30 - 0
components/ExpansionPanelComponent.vue

@@ -0,0 +1,30 @@
+<template>
+     <v-expansion-panel>
+       <v-expansion-panel-header class="light_grey">
+         {{title}}
+       </v-expansion-panel-header>
+       <v-expansion-panel-content>
+         <v-row>
+           <slot></slot>
+         </v-row>
+       </v-expansion-panel-content>
+     </v-expansion-panel>
+ </template>
+
+<script lang="ts">
+    export default {
+      props: {
+        title:{
+          type: String,
+          required: true
+        }
+      },
+
+      setup(){
+      }
+    }
+</script>
+
+<style scoped>
+
+</style>

+ 74 - 0
components/FormComponent.vue

@@ -0,0 +1,74 @@
+<template>
+  <main>
+    <v-form
+      ref="form"
+      v-model="valid"
+      lazy-validation
+    >
+      <v-row>
+        <slot></slot>
+      </v-row>
+
+      <v-btn
+        class="mr-4 submitBtn"
+        @click="submit"
+      >
+        submit
+      </v-btn>
+    </v-form>
+
+   <AlertComponent type="success" v-if="saveOk">Sauvegarde Effectuée</AlertComponent>
+   <AlertComponent type="error" v-if="saveKo">Sauvegarde Echouée</AlertComponent>
+  </main>
+</template>
+
+<script lang="ts">
+  import {defineComponent, ref, toRef} from '@vue/composition-api'
+  import {Repository} from "@vuex-orm/core";
+
+  export default defineComponent({
+    props: {
+      repository:{
+        type: Object as () => Repository,
+        required: true
+      }
+    },
+    setup(){
+      const valid = true
+      const saveOk = ref(false)
+      const saveKo = ref(false)
+      return {
+        valid,
+        saveOk,
+        saveKo
+      }
+    },
+    methods:{
+      async submit(){
+
+        if(this.$refs.form.validate()){
+          const model = await this.repository.find(parseInt(this.$route.params.id));
+          const playload = model.$toJson();
+
+          this.$http.$put(`https://local.new.api.opentalent.fr/api/${model.$entity}/${this.$route.params.id}`, playload)
+            .then(()=>{
+              this.saveOk=true
+            }, () =>{
+              this.saveKo=true
+            })
+
+          setTimeout(()=>{
+            this.saveOk=false
+            this.saveKo=false
+          },2000)
+        }
+      }
+    }
+  })
+</script>
+
+<style scoped>
+  .submitBtn{
+    margin-top: 20px;
+  }
+</style>

+ 66 - 0
components/InputComponent.vue

@@ -0,0 +1,66 @@
+<template>
+  <v-col
+    cols="12"
+    sm="6"
+  >
+    <v-text-field
+      v-model="data[field]"
+      @change="update()"
+      color="purple darken-2"
+      :rules="rules"
+      required
+    ></v-text-field>
+  </v-col>
+</template>
+
+<script lang="ts">
+  import {unref, defineComponent, ref, watch, onUnmounted} from '@vue/composition-api'
+  import {Repository} from "@vuex-orm/core";
+  import {cloneAndFlatten, cloneAndNest} from "~/services/objectProperties";
+
+  export default defineComponent({
+    props: {
+      repository:{
+        type: Object as () => Repository,
+        required: true
+      },
+      field:{
+        type: String,
+        required: true
+      },
+      rules:{
+        type: Array,
+        required: false
+      }
+    },
+    setup({repository, field}, {root}){
+      const data = ref({})
+
+      const update = () => {
+        repository.update(cloneAndNest(unref(data)))
+      }
+
+      /* const unwatch = watch(
+        () => root.$store.state.entities.people.data,
+        (state, prevState) => {
+         unref(data)[field] = state
+        }
+      )
+      onUnmounted(() => {
+        unwatch()
+      }) */
+
+      return {
+        data,
+        update
+      }
+    },
+    async fetch() {
+      const data = await this.repository.find(parseInt(this.$route.params.id));
+      this.data = cloneAndFlatten(data);
+    }
+  })
+</script>
+
+<style scoped>
+</style>

+ 0 - 79
components/Logo.vue

@@ -1,79 +0,0 @@
-<template>
-  <div class="VueToNuxtLogo">
-    <div class="Triangle Triangle--two" />
-    <div class="Triangle Triangle--one" />
-    <div class="Triangle Triangle--three" />
-    <div class="Triangle Triangle--four" />
-  </div>
-</template>
-
-<style>
-.VueToNuxtLogo {
-  display: inline-block;
-  animation: turn 2s linear forwards 1s;
-  transform: rotateX(180deg);
-  position: relative;
-  overflow: hidden;
-  height: 180px;
-  width: 245px;
-}
-
-.Triangle {
-  position: absolute;
-  top: 0;
-  left: 0;
-  width: 0;
-  height: 0;
-}
-
-.Triangle--one {
-  border-left: 105px solid transparent;
-  border-right: 105px solid transparent;
-  border-bottom: 180px solid #41b883;
-}
-
-.Triangle--two {
-  top: 30px;
-  left: 35px;
-  animation: goright 0.5s linear forwards 3.5s;
-  border-left: 87.5px solid transparent;
-  border-right: 87.5px solid transparent;
-  border-bottom: 150px solid #3b8070;
-}
-
-.Triangle--three {
-  top: 60px;
-  left: 35px;
-  animation: goright 0.5s linear forwards 3.5s;
-  border-left: 70px solid transparent;
-  border-right: 70px solid transparent;
-  border-bottom: 120px solid #35495e;
-}
-
-.Triangle--four {
-  top: 120px;
-  left: 70px;
-  animation: godown 0.5s linear forwards 3s;
-  border-left: 35px solid transparent;
-  border-right: 35px solid transparent;
-  border-bottom: 60px solid #fff;
-}
-
-@keyframes turn {
-  100% {
-    transform: rotateX(0deg);
-  }
-}
-
-@keyframes godown {
-  100% {
-    top: 180px;
-  }
-}
-
-@keyframes goright {
-  100% {
-    left: 70px;
-  }
-}
-</style>

+ 0 - 7
components/README.md

@@ -1,7 +0,0 @@
-# COMPONENTS
-
-**This directory is not required, you can delete it if you don't want to use it.**
-
-The components directory contains your Vue.js Components.
-
-_Nuxt.js doesn't supercharge these components._

+ 0 - 22
components/VuetifyLogo.vue

@@ -1,22 +0,0 @@
-<template>
-  <img
-    class="VuetifyLogo"
-    alt="Vuetify Logo"
-    src="/vuetify-logo.svg"
-  >
-</template>
-
-<style>
-.VuetifyLogo {
-  height: 180px;
-  width: 180px;
-  transform: rotateY(560deg);
-  animation: turn 3.5s ease-out forwards 1s;
-}
-
-@keyframes turn {
-  100% {
-    transform: rotateY(0deg);
-  }
-}
-</style>

+ 24 - 0
data/accessesData.js

@@ -0,0 +1,24 @@
+export default async function accessesData() {
+  return {
+    "@context": "\/api\/contexts\/Access",
+    "@id": "\/api\/accesses\/64",
+    "@type": "Access",
+    "id": 64,
+    "person": {
+      "@type": "Person",
+      "@id": "_:771",
+      "id": 552581,
+      "username": "",
+      "roles": [
+        "ROLE_USER"
+      ],
+      "name": "BLONDAZ PIEDIGROS",
+      "givenName": "Sylvie",
+      "__isInitialized__": true
+    },
+    "personActivity": [
+      "\/api\/person_activities\/58",
+      "\/api\/person_activities\/59"
+    ]
+  }
+}

+ 26 - 0
data/personActivitiesData.js

@@ -0,0 +1,26 @@
+export default async function personActivitiesData(){
+  return {
+    "@context": "\/api\/contexts\/PersonActivity",
+    "@id": "\/api\/accesses\/64\/person_activities",
+    "@type": "hydra:Collection",
+    "hydra:member": [
+      {
+        "@id": "\/api\/person_activities\/58",
+        "@type": "PersonActivity",
+        "id": 58,
+        "complementSpeciality": "Trompette",
+        "startDate": "1977-09-01T00:00:00+00:00",
+        "access": "\/api\/accesses\/64"
+      },
+      {
+        "@id": "\/api\/person_activities\/59",
+        "@type": "PersonActivity",
+        "id": 59,
+        "complementSpeciality": "Guitare",
+        "startDate": "2015-09-02T00:00:00+00:00",
+        "access": "\/api\/accesses\/64"
+      }
+    ],
+    "hydra:totalItems": 2
+  }
+}

+ 2 - 0
jest.config.js

@@ -5,11 +5,13 @@ module.exports = {
     '^vue$': 'vue/dist/vue.common.js'
   },
   moduleFileExtensions: [
+    'ts',
     'js',
     'vue',
     'json'
   ],
   transform: {
+    '^.+\\.ts$': 'ts-jest',
     '^.+\\.js$': 'babel-jest',
     '.*\\.(vue)$': 'vue-jest'
   },

+ 39 - 69
layouts/default.vue

@@ -1,9 +1,9 @@
 <template>
   <v-app dark>
     <v-navigation-drawer
-      v-model="drawer"
       :mini-variant="miniVariant"
       :clipped="clipped"
+      class="dark_grey"
       fixed
       app
     >
@@ -16,102 +16,72 @@
           exact
         >
           <v-list-item-action>
-            <v-icon>{{ item.icon }}</v-icon>
+            <v-icon class="navigation">{{ item.icon }}</v-icon>
           </v-list-item-action>
           <v-list-item-content>
-            <v-list-item-title v-text="item.title" />
+            <v-list-item-title class="navigation" v-text="item.title" />
           </v-list-item-content>
         </v-list-item>
       </v-list>
     </v-navigation-drawer>
+
     <v-app-bar
       :clipped-left="clipped"
       fixed
       app
+      class="green header"
     >
-      <v-app-bar-nav-icon @click.stop="drawer = !drawer" />
       <v-btn
         icon
         @click.stop="miniVariant = !miniVariant"
       >
         <v-icon>mdi-{{ `chevron-${miniVariant ? 'right' : 'left'}` }}</v-icon>
       </v-btn>
-      <v-btn
-        icon
-        @click.stop="clipped = !clipped"
-      >
-        <v-icon>mdi-application</v-icon>
-      </v-btn>
-      <v-btn
-        icon
-        @click.stop="fixed = !fixed"
-      >
-        <v-icon>mdi-minus</v-icon>
-      </v-btn>
+
+
       <v-toolbar-title v-text="title" />
       <v-spacer />
-      <v-btn
-        icon
-        @click.stop="rightDrawer = !rightDrawer"
-      >
-        <v-icon>mdi-menu</v-icon>
-      </v-btn>
+
     </v-app-bar>
-    <v-main>
+    <v-main class="super_light_grey">
       <v-container>
         <nuxt />
       </v-container>
     </v-main>
-    <v-navigation-drawer
-      v-model="rightDrawer"
-      :right="right"
-      temporary
-      fixed
-    >
-      <v-list>
-        <v-list-item @click.native="right = !right">
-          <v-list-item-action>
-            <v-icon light>
-              mdi-repeat
-            </v-icon>
-          </v-list-item-action>
-          <v-list-item-title>Switch drawer (click me)</v-list-item-title>
-        </v-list-item>
-      </v-list>
-    </v-navigation-drawer>
-    <v-footer
-      :absolute="!fixed"
-      app
-    >
-      <span>&copy; {{ new Date().getFullYear() }}</span>
-    </v-footer>
+
   </v-app>
 </template>
 
 <script>
-export default {
-  data () {
-    return {
-      clipped: false,
-      drawer: false,
-      fixed: false,
-      items: [
-        {
-          icon: 'mdi-apps',
-          title: 'Welcome',
-          to: '/'
-        },
-        {
-          icon: 'mdi-chart-bubble',
-          title: 'Inspire',
-          to: '/inspire'
-        }
-      ],
-      miniVariant: false,
-      right: true,
-      rightDrawer: false,
-      title: 'Vuetify.js'
+  export default {
+    data () {
+      return {
+        clipped: true,
+        fixed: true,
+        items: [
+          {
+            icon: 'mdi-apps',
+            title: 'Accueil',
+            to: '/'
+          },
+          {
+            icon: 'mdi-chart-bubble',
+            title: 'Répertoire',
+            to: '/accesses/list'
+          }
+        ],
+        miniVariant: false,
+        title: 'Etablissement d\'Enseignement Artistique'
+      }
     }
   }
-}
 </script>
+
+<style scoped>
+  .navigation{
+    color:#b8c7ce;
+  }
+  .header{
+    color:#ffffff;
+  }
+</style>

+ 23 - 23
layouts/error.vue

@@ -13,32 +13,32 @@
 </template>
 
 <script>
-export default {
-  layout: 'empty',
-  props: {
-    error: {
-      type: Object,
-      default: null
-    }
-  },
-  data () {
-    return {
-      pageNotFound: '404 Not Found',
-      otherError: 'An error occurred'
-    }
-  },
-  head () {
-    const title =
-      this.error.statusCode === 404 ? this.pageNotFound : this.otherError
-    return {
-      title
+  export default {
+    layout: 'empty',
+    props: {
+      error: {
+        type: Object,
+        default: null
+      }
+    },
+    data () {
+      return {
+        pageNotFound: '404 Not Found',
+        otherError: 'An error occurred'
+      }
+    },
+    head () {
+      const title =
+        this.error.statusCode === 404 ? this.pageNotFound : this.otherError
+      return {
+        title
+      }
     }
   }
-}
 </script>
 
 <style scoped>
-h1 {
-  font-size: 20px;
-}
+  h1 {
+    font-size: 20px;
+  }
 </style>

+ 12 - 0
models/Access.ts

@@ -0,0 +1,12 @@
+import {Model, Attr, HasOne, BelongsTo, Str} from '@vuex-orm/core'
+import {Person} from '@/models/Person'
+
+export class Access extends Model{
+  static entity = 'accesses'
+
+  @Attr(null)
+  id!: number | null
+
+  @HasOne(() => Person, 'accessId')
+  person: Person | null
+}

+ 17 - 0
models/Organization.ts

@@ -0,0 +1,17 @@
+import {Model, Attr, Str} from '@vuex-orm/core'
+
+export class Organization extends Model{
+  static entity = 'organizations'
+
+  @Attr(null)
+  id!: number | null
+
+  @Str('', {nullable: false})
+  name!: string
+
+  @Str('', {nullable: true})
+  legalStatus!: string
+
+  @Str('', {nullable: true})
+  principalType!: string
+}

+ 17 - 0
models/Person.ts

@@ -0,0 +1,17 @@
+import {Model, Attr, Str} from '@vuex-orm/core'
+
+export class Person extends Model{
+  static entity = 'people'
+
+  @Attr(null)
+  id!: number | null
+
+  @Attr(null)
+  accessId!: number | null
+
+  @Str('', {nullable: false})
+  name!: string
+
+  @Str('', {nullable: true})
+  givenName!: string
+}

+ 14 - 0
models/PersonActivity.ts

@@ -0,0 +1,14 @@
+import {Model, Attr, Str} from '@vuex-orm/core'
+
+export class PersonActivity extends Model{
+  static entity = 'person_activities'
+
+  @Attr(null)
+  id!: number | null
+
+  @Str('', {nullable: true})
+  startDate!: string
+
+  @Str('', {nullable: true})
+  complementSpeciality!: string
+}

+ 33 - 3
nuxt.config.js

@@ -24,6 +24,7 @@ export default {
 
   // Plugins to run before rendering page (https://go.nuxtjs.dev/config-plugins)
   plugins: [
+    '@/plugins/composition-api'
   ],
 
   // Auto import components (https://go.nuxtjs.dev/config-components)
@@ -31,19 +32,22 @@ export default {
 
   // Modules for dev and build (recommended) (https://go.nuxtjs.dev/config-modules)
   buildModules: [
+    // https://go.nuxtjs.dev/typescript
+    '@nuxt/typescript-build',
     // https://go.nuxtjs.dev/vuetify
-    '@nuxtjs/vuetify',
+    '@nuxtjs/vuetify'
   ],
 
   // Modules (https://go.nuxtjs.dev/config-modules)
   modules: [
+    '@nuxt/http'
   ],
 
   // Vuetify module configuration (https://go.nuxtjs.dev/config-vuetify)
   vuetify: {
     customVariables: ['~/assets/variables.scss'],
     theme: {
-      dark: true,
+      dark: false,
       themes: {
         dark: {
           primary: colors.blue.darken2,
@@ -53,12 +57,38 @@ export default {
           warning: colors.amber.base,
           error: colors.deepOrange.accent4,
           success: colors.green.accent3
-        }
+        },
+        light: {
+          green: '#00ad8e',
+          light_green: '#a9e0d6',
+          dark_grey: '#2c3a48',
+          grey: '#777777',
+          light_grey: '#f5f5f5',
+          super_light_grey: '#ecf0f5',
+          danger: '#f56954',
+          success: '#00a65a',
+          warning: '#f39c12',
+          info: '#3c8dbc'
+        },
       }
     }
   },
 
   // Build Configuration (https://go.nuxtjs.dev/config-build)
   build: {
+  },
+
+  //Port and local host
+  server: {
+    port: 3002,
+    host: '0.0.0.0', // default: localhost,
+  },
+
+  //Poll for hot reloading with docker
+  watchers: {
+    webpack: {
+      aggregateTimeout: 300,
+      poll: 1000
+    }
   }
 }

+ 20 - 5
package.json

@@ -3,22 +3,37 @@
   "version": "1.0.0",
   "private": true,
   "scripts": {
-    "dev": "nuxt",
-    "build": "nuxt build",
-    "start": "nuxt start",
-    "generate": "nuxt generate",
+    "dev": "nuxt-ts",
+    "build": "nuxt-ts build",
+    "start": "nuxt-ts start",
+    "generate": "nuxt-ts generate",
+    "lint:js": "eslint --ext .js,.vue --ignore-path .gitignore .",
+    "lint": "yarn lint:js",
     "test": "jest"
   },
   "dependencies": {
+    "@nuxt/http": "^0.6.1",
+    "@nuxt/typescript-runtime": "^2.0.0",
+    "@vue/composition-api": "^1.0.0-beta.21",
+    "@vuex-orm/core": "1.0.0-draft.6",
     "core-js": "^3.6.5",
     "nuxt": "^2.14.6"
   },
   "devDependencies": {
+    "@nuxt/types": "^2.14.6",
+    "@nuxt/typescript-build": "^2.0.3",
+    "@nuxtjs/eslint-config": "^3.1.0",
+    "@nuxtjs/eslint-config-typescript": "^3.0.0",
+    "@nuxtjs/eslint-module": "^2.0.0",
     "@nuxtjs/vuetify": "^1.11.2",
     "@vue/test-utils": "^1.1.0",
     "babel-core": "7.0.0-bridge.0",
+    "babel-eslint": "^10.1.0",
     "babel-jest": "^26.5.0",
+    "eslint": "^7.10.0",
+    "eslint-plugin-nuxt": "^1.0.0",
     "jest": "^26.5.0",
+    "ts-jest": "^26.4.1",
     "vue-jest": "^3.0.4"
   }
-}
+}

+ 82 - 0
pages/accesses/_id.vue

@@ -0,0 +1,82 @@
+<template>
+  <v-row justify="center" align="center">
+    <v-col cols="12" sm="8" md="8">
+
+        <FormComponent :repository="accessesRepository">
+
+          <v-expansion-panels v-model="panel" focusable>
+
+            <ExpansionPanelComponent title="Informations générales">
+              <InputComponent :repository="accessesRepository" field="person.name" :rules="nameRule" />
+              <InputComponent :repository="accessesRepository" field="person.givenName" />
+            </ExpansionPanelComponent>
+
+            <ExpansionPanelComponent title="Activités">
+              <DataTableComponent :repository="personActivitiesRepository" :uri="personActivitiesUri" :headers="personActivitiesHearders"></DataTableComponent>
+            </ExpansionPanelComponent>
+
+          </v-expansion-panels>
+
+        </FormComponent>
+
+    </v-col>
+  </v-row>
+</template>
+
+
+<script>
+  import {defineComponent} from '@vue/composition-api'
+  import {Access} from '@/models/Access'
+  import {Person} from '@/models/Person'
+  import {PersonActivity} from '@/models/PersonActivity'
+  import accessesData from '@/data/accessesData'
+
+  export default defineComponent({
+    setup(props, {root}) {
+      const panel = 0
+      const accessesRepository = root.$store.$repo(Access).with('person')
+      const personActivitiesRepository = root.$store.$repo(PersonActivity)
+
+      const personActivitiesUri = `${accessesRepository.model.$entity}/${root.$route.params.id}/${personActivitiesRepository.model.$entity}`
+      const personActivitiesHearders = [
+        {
+          text: 'Activité',
+          align: 'start',
+          sortable: false,
+          value: 'complementSpeciality',
+        },
+        { text: 'Date de début',
+          value: 'startDate'
+        }
+      ]
+
+      const nameRule = [
+        nameValue => (nameValue || '').length <= 128 || `A maximum of 128 characters is allowed`
+      ]
+
+      return {
+        accessesRepository,
+        personActivitiesRepository,
+        personActivitiesUri,
+        personActivitiesHearders,
+        panel,
+        nameRule
+      }
+    },
+
+    async asyncData({store, $http, params}){
+      const repository = store.$repo(Access);
+      // const entity = repository.model.$entity;
+      // const accesses = await $http.$get(`https://local.new.api.opentalent.fr/api/${entity}/${params.id}`)
+      const accesses = await accessesData()
+      repository.insert(accesses);
+    },
+
+    async beforeRouteLeave (to, from, next) {
+      const flushAccess =  await this.$store.$repo(Access).flush();
+      const flushPerson =  await this.$store.$repo(Person).flush();
+      const flushPersonActivity =  await this.$store.$repo(PersonActivity).flush();
+      next(true);
+    }
+  })
+</script>

+ 19 - 0
pages/accesses/list.vue

@@ -0,0 +1,19 @@
+<template>
+  <v-row justify="center" align="center">
+    <v-col cols="12" sm="12" md="12">
+      <h3><NuxtLink to="/accesses/64">Fiche d'une personne</NuxtLink></h3>
+    </v-col>
+  </v-row>
+</template>
+
+
+<script lang="ts">
+  import {defineComponent} from '@vue/composition-api'
+
+  export default defineComponent({
+    setup() {
+      return {
+      }
+    },
+  })
+</script>

+ 12 - 81
pages/index.vue

@@ -1,89 +1,20 @@
 <template>
   <v-row justify="center" align="center">
-    <v-col cols="12" sm="8" md="6">
-      <div class="text-center">
-        <logo />
-        <vuetify-logo />
-      </div>
-      <v-card>
-        <v-card-title class="headline">
-          Welcome to the Vuetify + Nuxt.js template
-        </v-card-title>
-        <v-card-text>
-          <p>Vuetify is a progressive Material Design component framework for Vue.js. It was designed to empower developers to create amazing applications.</p>
-          <p>
-            For more information on Vuetify, check out the <a
-              href="https://vuetifyjs.com"
-              target="_blank"
-              rel="noopener noreferrer"
-            >
-              documentation
-            </a>.
-          </p>
-          <p>
-            If you have questions, please join the official <a
-              href="https://chat.vuetifyjs.com/"
-              target="_blank"
-              rel="noopener noreferrer"
-              title="chat"
-            >
-              discord
-            </a>.
-          </p>
-          <p>
-            Find a bug? Report it on the github <a
-              href="https://github.com/vuetifyjs/vuetify/issues"
-              target="_blank"
-              rel="noopener noreferrer"
-              title="contribute"
-            >
-              issue board
-            </a>.
-          </p>
-          <p>Thank you for developing with Vuetify and I look forward to bringing more exciting features in the future.</p>
-          <div class="text-xs-right">
-            <em><small>&mdash; John Leider</small></em>
-          </div>
-          <hr class="my-3">
-          <a
-            href="https://nuxtjs.org/"
-            target="_blank"
-            rel="noopener noreferrer"
-          >
-            Nuxt Documentation
-          </a>
-          <br>
-          <a
-            href="https://github.com/nuxt/nuxt.js"
-            target="_blank"
-            rel="noopener noreferrer"
-          >
-            Nuxt GitHub
-          </a>
-        </v-card-text>
-        <v-card-actions>
-          <v-spacer />
-          <v-btn
-            color="primary"
-            nuxt
-            to="/inspire"
-          >
-            Continue
-          </v-btn>
-        </v-card-actions>
-      </v-card>
+    <v-col cols="12" sm="12" md="12">
+      <h3>Bienvenue !</h3>
     </v-col>
   </v-row>
 </template>
 
-<script>
-import Logo from '~/components/Logo.vue'
-import VuetifyLogo from '~/components/VuetifyLogo.vue'
 
-export default {
-  components: {
-    Logo,
-    VuetifyLogo
-  }
-}
+<script lang="ts">
+  import {defineComponent} from '@vue/composition-api'
+
+  export default defineComponent({
+    setup(props) {
+      return {
+      }
+    },
+  })
+
 </script>

+ 0 - 19
pages/inspire.vue

@@ -1,19 +0,0 @@
-<template>
-  <v-row>
-    <v-col class="text-center">
-      <img
-        src="/v.png"
-        alt="Vuetify.js"
-        class="mb-5"
-      >
-      <blockquote class="blockquote">
-        &#8220;First, solve the problem. Then, write the code.&#8221;
-        <footer>
-          <small>
-            <em>&mdash;John Johnson</em>
-          </small>
-        </footer>
-      </blockquote>
-    </v-col>
-  </v-row>
-</template>

+ 4 - 0
plugins/composition-api.js

@@ -0,0 +1,4 @@
+import Vue from 'vue'
+import VueCompositionApi from '@vue/composition-api'
+
+Vue.use(VueCompositionApi)

+ 81 - 0
services/objectProperties.js

@@ -0,0 +1,81 @@
+function isObject(value) {
+    if (value === null) return false;
+    if (typeof value !== 'object') return false;
+    if (Array.isArray(value)) return false;
+    if (Object.prototype.toString.call(value) === '[object Date]') return false;
+    return true;
+}
+
+export function clone(object) {
+    return Object.keys(object).reduce((values, name) => {
+        if (object.hasOwnProperty(name)) {
+            values[name] = object[name];
+        }
+        return values;
+    }, {});
+}
+
+/*
+ * Flatten nested object into a single level object with 'foo.bar' property names
+ *
+ * The parameter object is left unchanged. All values in the returned object are scalar.
+ *
+ *     cloneAndFlatten({ a: 1, b: { c: 2 }, d: { e: 3, f: { g: 4, h: 5 } }, i: { j: 6 } }, ['i'])
+ *     // { a: 1, 'b.c': 2, 'd.e': 3, 'd.f.g': 4, 'd.f.h': 5, i: { j: 6 } } }
+ *
+ * @param {Object} object
+ * @param {String[]} excludedProperties
+ * @return {Object}
+ */
+export function cloneAndFlatten(object, excludedProperties = []) {
+    if (typeof object !== 'object') {
+        throw new Error('Expecting an object parameter');
+    }
+    return Object.keys(object).reduce((values, name) => {
+        if (!object.hasOwnProperty(name)) return values;
+        if (isObject(object[name])) {
+            if (excludedProperties.indexOf(name) === -1) {
+                let flatObject = cloneAndFlatten(object[name]);
+                Object.keys(flatObject).forEach(flatObjectKey => {
+                    if (!flatObject.hasOwnProperty(flatObjectKey)) return;
+                    values[name + '.' + flatObjectKey] = flatObject[flatObjectKey];
+                })
+            } else {
+                values[name] = clone(object[name]);
+            }
+        } else {
+            values[name] = object[name];
+        }
+        return values;
+    }, {});
+};
+
+/*
+ * Clone flattened object into a nested object
+ *
+ * The parameter object is left unchanged.
+ *
+ *     cloneAndNest({ a: 1, 'b.c': 2, 'd.e': 3, 'd.f.g': 4, 'd.f.h': 5 } )
+ *     // { a: 1, b: { c: 2 }, d: { e: 3, f: { g: 4, h: 5 } } }
+ *
+ * @param {Object} object
+ * @return {Object}
+ */
+export function cloneAndNest(object) {
+    if (typeof object !== 'object') {
+        throw new Error('Expecting an object parameter');
+    }
+    return Object.keys(object).reduce((values, name) => {
+        if (!object.hasOwnProperty(name)) return values;
+        name.split('.').reduce((previous, current, index, list) => {
+            if (previous != null) {
+                if (typeof previous[current] === 'undefined') previous[current] = {};
+                if (index < (list.length - 1)) {
+                    return previous[current];
+                };
+                previous[current] = object[name];
+            }
+        }, values)
+        return values;
+    }, {})
+}

+ 0 - 11
static/README.md

@@ -1,11 +0,0 @@
-# STATIC
-
-**This directory is not required, you can delete it if you don't want to use it.**
-
-This directory contains your static files.
-Each file inside this directory is mapped to `/`.
-Thus you'd want to delete this README.md before deploying to production.
-
-Example: `/static/robots.txt` is mapped as `/robots.txt`.
-
-More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/assets#static).

BIN
static/favicon.ico


BIN
static/v.png


+ 0 - 1
static/vuetify-logo.svg

@@ -1 +0,0 @@
-<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 87.5 100"><defs><style>.cls-1{fill:#1697f6;}.cls-2{fill:#7bc6ff;}.cls-3{fill:#1867c0;}.cls-4{fill:#aeddff;}</style></defs><title>Artboard 46</title><polyline class="cls-1" points="43.75 0 23.31 0 43.75 48.32"/><polygon class="cls-2" points="43.75 62.5 43.75 100 0 14.58 22.92 14.58 43.75 62.5"/><polyline class="cls-3" points="43.75 0 64.19 0 43.75 48.32"/><polygon class="cls-4" points="64.58 14.58 87.5 14.58 43.75 100 43.75 62.5 64.58 14.58"/></svg>

+ 0 - 10
store/README.md

@@ -1,10 +0,0 @@
-# STORE
-
-**This directory is not required, you can delete it if you don't want to use it.**
-
-This directory contains your Vuex Store files.
-Vuex Store option is implemented in the Nuxt.js framework.
-
-Creating a file in this directory automatically activates the option in the framework.
-
-More information about the usage of this directory in [the documentation](https://nuxtjs.org/guide/vuex-store).

+ 5 - 0
store/index.js

@@ -0,0 +1,5 @@
+import VuexORM from '@vuex-orm/core'
+
+export const plugins = [
+  VuexORM.install()
+];

+ 37 - 0
tsconfig.json

@@ -0,0 +1,37 @@
+{
+  "compilerOptions": {
+    "target": "ES2018",
+    "module": "ESNext",
+    "moduleResolution": "Node",
+    "lib": [
+      "ESNext",
+      "ESNext.AsyncIterable",
+      "DOM"
+    ],
+    "esModuleInterop": true,
+    "allowJs": true,
+    "sourceMap": true,
+    "strict": true,
+    "noEmit": true,
+    "experimentalDecorators": true,
+    "baseUrl": ".",
+    "paths": {
+      "~/*": [
+        "./*"
+      ],
+      "@/*": [
+        "./*"
+      ]
+    },
+    "types": [
+      "@types/node",
+      "@nuxt/types",
+      "@nuxtjs/vuetify"
+    ]
+  },
+  "exclude": [
+    "node_modules",
+    ".nuxt",
+    "dist"
+  ]
+}

+ 4 - 0
types/vue-shim.d.ts

@@ -0,0 +1,4 @@
+declare module "*.vue" {
+  import Vue from 'vue'
+  export default Vue
+}

File diff suppressed because it is too large
+ 743 - 14
yarn.lock


Some files were not shown because too many files changed in this diff