parent
							
								
									a1bcb12f20
								
							
						
					
					
						commit
						053bcad80a
					
				@ -0,0 +1,78 @@ | 
				
			|||||||
 | 
					<template> | 
				
			||||||
 | 
					        <v-app id="inspire"> | 
				
			||||||
 | 
					            <snackbar></snackbar> | 
				
			||||||
 | 
					            <v-navigation-drawer v-model="drawer" app> | 
				
			||||||
 | 
					                <v-list dense> | 
				
			||||||
 | 
					                    <v-list-item> | 
				
			||||||
 | 
					                        <v-list-item-action> | 
				
			||||||
 | 
					                            <v-icon>mdi-home</v-icon> | 
				
			||||||
 | 
					                        </v-list-item-action> | 
				
			||||||
 | 
					                        <v-list-item-content> | 
				
			||||||
 | 
					                            <v-list-item-title>Home</v-list-item-title> | 
				
			||||||
 | 
					                        </v-list-item-content> | 
				
			||||||
 | 
					                    </v-list-item> | 
				
			||||||
 | 
					                    <v-list-item> | 
				
			||||||
 | 
					                        <v-list-item-action> | 
				
			||||||
 | 
					                            <v-icon>mdi-book</v-icon> | 
				
			||||||
 | 
					                        </v-list-item-action> | 
				
			||||||
 | 
					                        <v-list-item-content> | 
				
			||||||
 | 
					                            <v-list-item-title> | 
				
			||||||
 | 
					                                <router-link :to="{ name: 'CourseList' }">Courses</router-link> | 
				
			||||||
 | 
					                            </v-list-item-title> | 
				
			||||||
 | 
					                        </v-list-item-content> | 
				
			||||||
 | 
					                    </v-list-item> | 
				
			||||||
 | 
					                    <v-list-item> | 
				
			||||||
 | 
					                        <v-list-item-action> | 
				
			||||||
 | 
					                            <v-icon>mdi-book</v-icon> | 
				
			||||||
 | 
					                        </v-list-item-action> | 
				
			||||||
 | 
					                        <v-list-item-content> | 
				
			||||||
 | 
					                            <v-list-item-title> | 
				
			||||||
 | 
					                                <router-link :to="{ name: 'CourseCategoryList' }">Courses category</router-link> | 
				
			||||||
 | 
					                            </v-list-item-title> | 
				
			||||||
 | 
					                        </v-list-item-content> | 
				
			||||||
 | 
					                    </v-list-item> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <v-list-item> | 
				
			||||||
 | 
					                        <v-list-item-action> | 
				
			||||||
 | 
					                            <v-icon>mdi-comment-quote</v-icon> | 
				
			||||||
 | 
					                        </v-list-item-action> | 
				
			||||||
 | 
					                        <v-list-item-content> | 
				
			||||||
 | 
					                            <v-list-item-title> | 
				
			||||||
 | 
					                                <router-link :to="{ name: 'ReviewList' }">Reviews</router-link> | 
				
			||||||
 | 
					                            </v-list-item-title> | 
				
			||||||
 | 
					                        </v-list-item-content> | 
				
			||||||
 | 
					                    </v-list-item> | 
				
			||||||
 | 
					                </v-list> | 
				
			||||||
 | 
					            </v-navigation-drawer> | 
				
			||||||
 | 
					            <v-app-bar app color="indigo" dark> | 
				
			||||||
 | 
					                <v-app-bar-nav-icon @click.stop="drawer = !drawer"></v-app-bar-nav-icon> | 
				
			||||||
 | 
					                <v-toolbar-title>Application</v-toolbar-title> | 
				
			||||||
 | 
					            </v-app-bar> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <v-content> | 
				
			||||||
 | 
					                <Breadcrumb layout-class="pl-3 py-3" /> | 
				
			||||||
 | 
					                <router-view></router-view> | 
				
			||||||
 | 
					            </v-content> | 
				
			||||||
 | 
					            <v-footer color="indigo" app> | 
				
			||||||
 | 
					                <span class="white--text">© 2019</span> | 
				
			||||||
 | 
					            </v-footer> | 
				
			||||||
 | 
					        </v-app> | 
				
			||||||
 | 
					</template> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script> | 
				
			||||||
 | 
					    import Breadcrumb from './components/Breadcrumb'; | 
				
			||||||
 | 
					    import Snackbar from './components/Snackbar'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    export default { | 
				
			||||||
 | 
					        name: "App", | 
				
			||||||
 | 
					        components: { | 
				
			||||||
 | 
					            Breadcrumb, | 
				
			||||||
 | 
					            Snackbar | 
				
			||||||
 | 
					        }, | 
				
			||||||
 | 
					        data: () => ({ | 
				
			||||||
 | 
					            drawer: null | 
				
			||||||
 | 
					        }), | 
				
			||||||
 | 
					        beforeMount() { | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					</script> | 
				
			||||||
@ -0,0 +1,3 @@ | 
				
			|||||||
 | 
					 export const VueConfig = { | 
				
			||||||
 | 
					   delimiters: ['[[', ']]'] | 
				
			||||||
 | 
					 }; | 
				
			||||||
@ -0,0 +1,45 @@ | 
				
			|||||||
 | 
					<template> | 
				
			||||||
 | 
					  <div> | 
				
			||||||
 | 
					    <v-row justify="space-around"> | 
				
			||||||
 | 
					      <v-icon v-if="handleShow" small class="mr-2" @click="handleShow">mdi-eye</v-icon> | 
				
			||||||
 | 
					      <v-icon v-if="handleEdit" small class="mr-2" @click="handleEdit">mdi-pencil</v-icon> | 
				
			||||||
 | 
					      <v-icon v-if="handleDelete" small @click="confirmDelete = true">mdi-delete</v-icon> | 
				
			||||||
 | 
					    </v-row> | 
				
			||||||
 | 
					    <ConfirmDelete | 
				
			||||||
 | 
					      v-if="handleDelete" | 
				
			||||||
 | 
					      :visible="confirmDelete" | 
				
			||||||
 | 
					      :handle-delete="handleDelete" | 
				
			||||||
 | 
					      @close="confirmDelete = false" | 
				
			||||||
 | 
					    /> | 
				
			||||||
 | 
					  </div> | 
				
			||||||
 | 
					</template> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script> | 
				
			||||||
 | 
					import ConfirmDelete from './ConfirmDelete'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default { | 
				
			||||||
 | 
					  name: 'ActionCell', | 
				
			||||||
 | 
					  components: { | 
				
			||||||
 | 
					    ConfirmDelete | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  data() { | 
				
			||||||
 | 
					    return { | 
				
			||||||
 | 
					      confirmDelete: false | 
				
			||||||
 | 
					    }; | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  props: { | 
				
			||||||
 | 
					    handleShow: { | 
				
			||||||
 | 
					      type: Function, | 
				
			||||||
 | 
					      required: false | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    handleEdit: { | 
				
			||||||
 | 
					      type: Function, | 
				
			||||||
 | 
					      required: false | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    handleDelete: { | 
				
			||||||
 | 
					      type: Function, | 
				
			||||||
 | 
					      required: false | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					}; | 
				
			||||||
 | 
					</script> | 
				
			||||||
@ -0,0 +1,40 @@ | 
				
			|||||||
 | 
					<template> | 
				
			||||||
 | 
					  <div> | 
				
			||||||
 | 
					    <v-breadcrumbs :items="items" divider="/" :class="layoutClass" /> | 
				
			||||||
 | 
					  </div> | 
				
			||||||
 | 
					</template> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script> | 
				
			||||||
 | 
					export default { | 
				
			||||||
 | 
					  name: 'Breadcrumb', | 
				
			||||||
 | 
					  props: ['layoutClass'], | 
				
			||||||
 | 
					  data() { | 
				
			||||||
 | 
					    return {}; | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  computed: { | 
				
			||||||
 | 
					    items() { | 
				
			||||||
 | 
					      const { path, matched } = this.$route; | 
				
			||||||
 | 
					      const items = [ | 
				
			||||||
 | 
					        { | 
				
			||||||
 | 
					          text: 'Home', | 
				
			||||||
 | 
					          href: '/' | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					      ]; | 
				
			||||||
 | 
					      const lastItem = matched[matched.length - 1]; | 
				
			||||||
 | 
					      for (let i = 0, len = matched.length; i < len; i += 1) { | 
				
			||||||
 | 
					        const route = matched[i]; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (route.path) { | 
				
			||||||
 | 
					          items.push({ | 
				
			||||||
 | 
					            text: route.name, | 
				
			||||||
 | 
					            disabled: route.path === path || lastItem.path === route.path, | 
				
			||||||
 | 
					            href: route.path | 
				
			||||||
 | 
					          }); | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					      } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return items; | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					}; | 
				
			||||||
 | 
					</script> | 
				
			||||||
@ -0,0 +1,45 @@ | 
				
			|||||||
 | 
					<template> | 
				
			||||||
 | 
					  <v-dialog v-model="show" persistent width="300"> | 
				
			||||||
 | 
					    <v-card> | 
				
			||||||
 | 
					      <v-card-text>{{ $t('Are you sure you want to delete this item?') }}</v-card-text> | 
				
			||||||
 | 
					      <v-card-actions> | 
				
			||||||
 | 
					        <v-spacer></v-spacer> | 
				
			||||||
 | 
					        <v-btn color="error darken-1" @click="handleDelete"> | 
				
			||||||
 | 
					          {{ $t('Delete') }} | 
				
			||||||
 | 
					        </v-btn> | 
				
			||||||
 | 
					        <v-btn color="secondary darken-1" text @click.stop="show = false"> | 
				
			||||||
 | 
					          {{ $t('Cancel') }} | 
				
			||||||
 | 
					        </v-btn> | 
				
			||||||
 | 
					      </v-card-actions> | 
				
			||||||
 | 
					    </v-card> | 
				
			||||||
 | 
					  </v-dialog> | 
				
			||||||
 | 
					</template> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script> | 
				
			||||||
 | 
					export default { | 
				
			||||||
 | 
					  name: 'ConfirmDelete', | 
				
			||||||
 | 
					  props: { | 
				
			||||||
 | 
					    visible: { | 
				
			||||||
 | 
					      type: Boolean, | 
				
			||||||
 | 
					      required: true, | 
				
			||||||
 | 
					      default: () => false | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    handleDelete: { | 
				
			||||||
 | 
					      type: Function, | 
				
			||||||
 | 
					      required: true | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  computed: { | 
				
			||||||
 | 
					    show: { | 
				
			||||||
 | 
					      get() { | 
				
			||||||
 | 
					        return this.visible; | 
				
			||||||
 | 
					      }, | 
				
			||||||
 | 
					      set(value) { | 
				
			||||||
 | 
					        if (!value) { | 
				
			||||||
 | 
					          this.$emit('close'); | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					      } | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					}; | 
				
			||||||
 | 
					</script> | 
				
			||||||
@ -0,0 +1,40 @@ | 
				
			|||||||
 | 
					<template> | 
				
			||||||
 | 
					  <v-expansion-panels v-model="filtersExpanded"> | 
				
			||||||
 | 
					    <v-expansion-panel> | 
				
			||||||
 | 
					      <v-expansion-panel-header> | 
				
			||||||
 | 
					        {{ $t('Filters') }} | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <template slot="actions"> | 
				
			||||||
 | 
					          <v-icon large>mdi-filter-variant</v-icon> | 
				
			||||||
 | 
					        </template> | 
				
			||||||
 | 
					      </v-expansion-panel-header> | 
				
			||||||
 | 
					      <v-expansion-panel-content> | 
				
			||||||
 | 
					        <slot name="filter"></slot> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <v-btn color="primary" @click="handleFilter">{{ $t('Filter')}}</v-btn> | 
				
			||||||
 | 
					        <v-btn color="primary" class="ml-2" text @click="handleReset">{{ $t('Reset') }}</v-btn> | 
				
			||||||
 | 
					      </v-expansion-panel-content> | 
				
			||||||
 | 
					    </v-expansion-panel> | 
				
			||||||
 | 
					  </v-expansion-panels> | 
				
			||||||
 | 
					</template> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script> | 
				
			||||||
 | 
					export default { | 
				
			||||||
 | 
					  name: 'DataFilter', | 
				
			||||||
 | 
					  props: { | 
				
			||||||
 | 
					    handleReset: { | 
				
			||||||
 | 
					      type: Function, | 
				
			||||||
 | 
					      required: true | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    handleFilter: { | 
				
			||||||
 | 
					      type: Function, | 
				
			||||||
 | 
					      required: true | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  data() { | 
				
			||||||
 | 
					    return { | 
				
			||||||
 | 
					      filtersExpanded: false | 
				
			||||||
 | 
					    }; | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					}; | 
				
			||||||
 | 
					</script> | 
				
			||||||
@ -0,0 +1,52 @@ | 
				
			|||||||
 | 
					<template> | 
				
			||||||
 | 
					  <v-menu | 
				
			||||||
 | 
					    v-model="showMenu" | 
				
			||||||
 | 
					    :close-on-content-click="false" | 
				
			||||||
 | 
					    :nudge-right="40" | 
				
			||||||
 | 
					    transition="scale-transition" | 
				
			||||||
 | 
					    offset-y | 
				
			||||||
 | 
					    min-width="290px" | 
				
			||||||
 | 
					  > | 
				
			||||||
 | 
					    <template v-slot:activator="{ on }"> | 
				
			||||||
 | 
					      <v-text-field | 
				
			||||||
 | 
					        v-model="date" | 
				
			||||||
 | 
					        :label="label" | 
				
			||||||
 | 
					        prepend-icon="mdi-calendar" | 
				
			||||||
 | 
					        readonly | 
				
			||||||
 | 
					        v-on="on" | 
				
			||||||
 | 
					      ></v-text-field> | 
				
			||||||
 | 
					    </template> | 
				
			||||||
 | 
					    <v-date-picker v-model="date" @input="handleInput"></v-date-picker> | 
				
			||||||
 | 
					  </v-menu> | 
				
			||||||
 | 
					</template> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script> | 
				
			||||||
 | 
					import { formatDateTime } from '../utils/dates'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default { | 
				
			||||||
 | 
					  props: { | 
				
			||||||
 | 
					    label: { | 
				
			||||||
 | 
					      type: String, | 
				
			||||||
 | 
					      required: false, | 
				
			||||||
 | 
					      default: () => '' | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    value: String | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  created() { | 
				
			||||||
 | 
					    this.date = this.value ? this.value : this.date; | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  data() { | 
				
			||||||
 | 
					    return { | 
				
			||||||
 | 
					      date: this.value ? this.value : new Date().toISOString().substr(0, 10), | 
				
			||||||
 | 
					      showMenu: false | 
				
			||||||
 | 
					    }; | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  methods: { | 
				
			||||||
 | 
					    formatDateTime, | 
				
			||||||
 | 
					    handleInput() { | 
				
			||||||
 | 
					      this.showMenu = false; | 
				
			||||||
 | 
					      this.$emit('input', this.date); | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					}; | 
				
			||||||
 | 
					</script> | 
				
			||||||
@ -0,0 +1,18 @@ | 
				
			|||||||
 | 
					<template> | 
				
			||||||
 | 
					  <div class="text-center"> | 
				
			||||||
 | 
					    <v-overlay :value="visible"> | 
				
			||||||
 | 
					      <v-progress-circular indeterminate size="64"></v-progress-circular> | 
				
			||||||
 | 
					    </v-overlay> | 
				
			||||||
 | 
					  </div> | 
				
			||||||
 | 
					</template> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script> | 
				
			||||||
 | 
					export default { | 
				
			||||||
 | 
					  props: { | 
				
			||||||
 | 
					    visible: { | 
				
			||||||
 | 
					      type: Boolean, | 
				
			||||||
 | 
					      required: true | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					}; | 
				
			||||||
 | 
					</script> | 
				
			||||||
@ -0,0 +1,32 @@ | 
				
			|||||||
 | 
					<template> | 
				
			||||||
 | 
					  <v-snackbar | 
				
			||||||
 | 
					    v-model="show" | 
				
			||||||
 | 
					    :color="color" | 
				
			||||||
 | 
					    :multi-line="true" | 
				
			||||||
 | 
					    :timeout="timeout" | 
				
			||||||
 | 
					    right | 
				
			||||||
 | 
					    top | 
				
			||||||
 | 
					  > | 
				
			||||||
 | 
					    {{ text }} | 
				
			||||||
 | 
					    <template v-if="subText"> | 
				
			||||||
 | 
					      <p>{{ subText }}</p> | 
				
			||||||
 | 
					    </template> | 
				
			||||||
 | 
					    <v-btn dark text @click.native="close">{{ $t('Close') }}</v-btn> | 
				
			||||||
 | 
					  </v-snackbar> | 
				
			||||||
 | 
					</template> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script> | 
				
			||||||
 | 
					import { mapFields } from 'vuex-map-fields'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default { | 
				
			||||||
 | 
					  computed: { | 
				
			||||||
 | 
					    ...mapFields('notifications', ['color', 'show', 'subText', 'text', 'timeout']) | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  methods: { | 
				
			||||||
 | 
					    close() { | 
				
			||||||
 | 
					      this.show = false; | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					}; | 
				
			||||||
 | 
					</script> | 
				
			||||||
@ -0,0 +1,137 @@ | 
				
			|||||||
 | 
					<template> | 
				
			||||||
 | 
					  <v-toolbar class="my-md-auto" elevation="0"> | 
				
			||||||
 | 
					    <slot name="left"></slot> | 
				
			||||||
 | 
					    <v-spacer /> | 
				
			||||||
 | 
					    <div> | 
				
			||||||
 | 
					      <v-btn | 
				
			||||||
 | 
					              v-if="handleList" | 
				
			||||||
 | 
					              :loading="isLoading" | 
				
			||||||
 | 
					              color="primary" | 
				
			||||||
 | 
					              @click="listItem" | 
				
			||||||
 | 
					      > | 
				
			||||||
 | 
					        {{ $t('List') }} | 
				
			||||||
 | 
					      </v-btn> | 
				
			||||||
 | 
					      <v-btn | 
				
			||||||
 | 
					        v-if="handleEdit" | 
				
			||||||
 | 
					        :loading="isLoading" | 
				
			||||||
 | 
					        color="primary" | 
				
			||||||
 | 
					        @click="editItem" | 
				
			||||||
 | 
					      > | 
				
			||||||
 | 
					        {{ $t('Edit') }} | 
				
			||||||
 | 
					      </v-btn> | 
				
			||||||
 | 
					      <v-btn | 
				
			||||||
 | 
					        v-if="handleSubmit" | 
				
			||||||
 | 
					        :loading="isLoading" | 
				
			||||||
 | 
					        color="primary" | 
				
			||||||
 | 
					        @click="submitItem" | 
				
			||||||
 | 
					      > | 
				
			||||||
 | 
					        <v-icon left>mdi-content-save</v-icon> | 
				
			||||||
 | 
					        {{ $t('Submit') }} | 
				
			||||||
 | 
					      </v-btn> | 
				
			||||||
 | 
					      <v-btn | 
				
			||||||
 | 
					        v-if="handleReset" | 
				
			||||||
 | 
					        color="primary" | 
				
			||||||
 | 
					        class="ml-sm-2" | 
				
			||||||
 | 
					        @click="resetItem" | 
				
			||||||
 | 
					      > | 
				
			||||||
 | 
					        {{ $t('Reset') }} | 
				
			||||||
 | 
					      </v-btn> | 
				
			||||||
 | 
					      <v-btn | 
				
			||||||
 | 
					        v-if="handleDelete" | 
				
			||||||
 | 
					        color="error" | 
				
			||||||
 | 
					        class="ml-sm-2" | 
				
			||||||
 | 
					        @click="confirmDelete = true" | 
				
			||||||
 | 
					      > | 
				
			||||||
 | 
					        {{ $t('Delete') }} | 
				
			||||||
 | 
					      </v-btn> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <v-btn v-if="handleAdd" color="primary" rounded @click="addItem"> | 
				
			||||||
 | 
					        <v-icon>mdi-plus-circle</v-icon> | 
				
			||||||
 | 
					      </v-btn> | 
				
			||||||
 | 
					    </div> | 
				
			||||||
 | 
					    <ConfirmDelete | 
				
			||||||
 | 
					      v-if="handleDelete" | 
				
			||||||
 | 
					      :visible="confirmDelete" | 
				
			||||||
 | 
					      :handle-delete="handleDelete" | 
				
			||||||
 | 
					      @close="confirmDelete = false" | 
				
			||||||
 | 
					    /> | 
				
			||||||
 | 
					  </v-toolbar> | 
				
			||||||
 | 
					</template> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script> | 
				
			||||||
 | 
					import ConfirmDelete from './ConfirmDelete'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default { | 
				
			||||||
 | 
					  name: 'Toolbar', | 
				
			||||||
 | 
					  components: { | 
				
			||||||
 | 
					    ConfirmDelete | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  data() { | 
				
			||||||
 | 
					    return { | 
				
			||||||
 | 
					      confirmDelete: false | 
				
			||||||
 | 
					    }; | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  props: { | 
				
			||||||
 | 
					    handleList: { | 
				
			||||||
 | 
					      type: Function, | 
				
			||||||
 | 
					      required: false | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    handleEdit: { | 
				
			||||||
 | 
					      type: Function, | 
				
			||||||
 | 
					      required: false | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    handleSubmit: { | 
				
			||||||
 | 
					      type: Function, | 
				
			||||||
 | 
					      required: false | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    handleReset: { | 
				
			||||||
 | 
					      type: Function, | 
				
			||||||
 | 
					      required: false | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    handleDelete: { | 
				
			||||||
 | 
					      type: Function, | 
				
			||||||
 | 
					      required: false | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    handleAdd: { | 
				
			||||||
 | 
					      type: Function, | 
				
			||||||
 | 
					      required: false | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    title: { | 
				
			||||||
 | 
					      type: String, | 
				
			||||||
 | 
					      required: false | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    isLoading: { | 
				
			||||||
 | 
					      type: Boolean, | 
				
			||||||
 | 
					      required: false, | 
				
			||||||
 | 
					      default: () => false | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  methods: { | 
				
			||||||
 | 
					    listItem() { | 
				
			||||||
 | 
					      if (this.handleList) { | 
				
			||||||
 | 
					        this.handleList(); | 
				
			||||||
 | 
					      } | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    addItem() { | 
				
			||||||
 | 
					      if (this.handleAdd) { | 
				
			||||||
 | 
					        this.handleAdd(); | 
				
			||||||
 | 
					      } | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    editItem() { | 
				
			||||||
 | 
					      if (this.handleEdit) { | 
				
			||||||
 | 
					        this.handleEdit(); | 
				
			||||||
 | 
					      } | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    submitItem() { | 
				
			||||||
 | 
					      if (this.handleSubmit) { | 
				
			||||||
 | 
					        this.handleSubmit(); | 
				
			||||||
 | 
					      } | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    resetItem() { | 
				
			||||||
 | 
					      if (this.handleReset) { | 
				
			||||||
 | 
					        this.handleReset(); | 
				
			||||||
 | 
					      } | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					}; | 
				
			||||||
 | 
					</script> | 
				
			||||||
@ -0,0 +1,76 @@ | 
				
			|||||||
 | 
					<template> | 
				
			||||||
 | 
					  <v-container fluid> | 
				
			||||||
 | 
					    <v-row> | 
				
			||||||
 | 
					      <v-col cols="12" sm="6" md="6"> | 
				
			||||||
 | 
					        <v-text-field | 
				
			||||||
 | 
					          v-model="item.title" | 
				
			||||||
 | 
					          :label="$t('title')" | 
				
			||||||
 | 
					          type="text" | 
				
			||||||
 | 
					        /> | 
				
			||||||
 | 
					      </v-col> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <v-col cols="12" sm="6" md="6"> | 
				
			||||||
 | 
					        <v-text-field | 
				
			||||||
 | 
					          v-model="item.code" | 
				
			||||||
 | 
					          :label="$t('code')" | 
				
			||||||
 | 
					          type="text" | 
				
			||||||
 | 
					        /> | 
				
			||||||
 | 
					      </v-col> | 
				
			||||||
 | 
					    </v-row> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <v-row> | 
				
			||||||
 | 
					      <v-col cols="12" sm="6" md="6"> | 
				
			||||||
 | 
					        <v-combobox | 
				
			||||||
 | 
					              v-model="item.category" | 
				
			||||||
 | 
					              :items="categorySelectItems" | 
				
			||||||
 | 
					              :no-data-text="$t('No results')" | 
				
			||||||
 | 
					              :label="$t('category')" | 
				
			||||||
 | 
					              item-text="name" | 
				
			||||||
 | 
					              item-value="@id" | 
				
			||||||
 | 
					          chips | 
				
			||||||
 | 
					        /> | 
				
			||||||
 | 
					      </v-col> | 
				
			||||||
 | 
					     | 
				
			||||||
 | 
					      <v-row cols="12"></v-row> | 
				
			||||||
 | 
					    </v-row> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  </v-container> | 
				
			||||||
 | 
					</template> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { mapActions, mapGetters } from 'vuex'; | 
				
			||||||
 | 
					import { mapFields } from 'vuex-map-fields'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default { | 
				
			||||||
 | 
					  name: 'CourseFilter', | 
				
			||||||
 | 
					  props: { | 
				
			||||||
 | 
					    values: { | 
				
			||||||
 | 
					      type: Object, | 
				
			||||||
 | 
					      required: true | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  data() { | 
				
			||||||
 | 
					    return {}; | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  mounted() { | 
				
			||||||
 | 
					    this.categoryGetSelectItems(); | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  methods: { | 
				
			||||||
 | 
					    ...mapActions({ | 
				
			||||||
 | 
					      categoryGetSelectItems: 'coursecategory/fetchSelectItems' | 
				
			||||||
 | 
					    }), | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  computed: { | 
				
			||||||
 | 
					    ...mapFields('coursecategory', { | 
				
			||||||
 | 
					      categorySelectItems: 'selectItems' | 
				
			||||||
 | 
					    }), | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // eslint-disable-next-line | 
				
			||||||
 | 
					    item() { | 
				
			||||||
 | 
					      return this.initialValues || this.values; | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					}; | 
				
			||||||
 | 
					</script> | 
				
			||||||
@ -0,0 +1,173 @@ | 
				
			|||||||
 | 
					<template> | 
				
			||||||
 | 
					  <v-form> | 
				
			||||||
 | 
					    <v-container fluid> | 
				
			||||||
 | 
					      <v-row> | 
				
			||||||
 | 
					        <v-col cols="12" sm="6" md="6"> | 
				
			||||||
 | 
					          <v-text-field | 
				
			||||||
 | 
					                  v-model="item.title" | 
				
			||||||
 | 
					                  :error-messages="titleErrors" | 
				
			||||||
 | 
					                  :label="$t('title')" | 
				
			||||||
 | 
					                  required | 
				
			||||||
 | 
					                  @input="$v.item.title.$touch()" | 
				
			||||||
 | 
					                  @blur="$v.item.title.$touch()" | 
				
			||||||
 | 
					          /> | 
				
			||||||
 | 
					        </v-col> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <v-col cols="12" sm="6" md="6"> | 
				
			||||||
 | 
					          <v-text-field | 
				
			||||||
 | 
					                  v-model="item.code" | 
				
			||||||
 | 
					                  :error-messages="codeErrors" | 
				
			||||||
 | 
					                  :label="$t('code')" | 
				
			||||||
 | 
					                  required | 
				
			||||||
 | 
					                  @input="$v.item.code.$touch()" | 
				
			||||||
 | 
					                  @blur="$v.item.code.$touch()" | 
				
			||||||
 | 
					          /> | 
				
			||||||
 | 
					        </v-col> | 
				
			||||||
 | 
					      </v-row> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <v-row> | 
				
			||||||
 | 
					        <v-col cols="12" sm="6" md="6"> | 
				
			||||||
 | 
					          <v-combobox | 
				
			||||||
 | 
					                  v-model="item.category" | 
				
			||||||
 | 
					                  :items="categorySelectItems" | 
				
			||||||
 | 
					                  :error-messages="categoryErrors" | 
				
			||||||
 | 
					                  :no-data-text="$t('No results')" | 
				
			||||||
 | 
					                  :label="$t('category')" | 
				
			||||||
 | 
					                  item-text="name" | 
				
			||||||
 | 
					                  item-value="@id" | 
				
			||||||
 | 
					          /> | 
				
			||||||
 | 
					        </v-col> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <v-col cols="12" sm="6" md="6"> | 
				
			||||||
 | 
					          <v-text-field | 
				
			||||||
 | 
					                  v-model.number="item.visibility" | 
				
			||||||
 | 
					                  :error-messages="visibilityErrors" | 
				
			||||||
 | 
					                  :label="$t('visibility')" | 
				
			||||||
 | 
					                  required | 
				
			||||||
 | 
					                  @input="$v.item.visibility.$touch()" | 
				
			||||||
 | 
					                  @blur="$v.item.visibility.$touch()" | 
				
			||||||
 | 
					          /> | 
				
			||||||
 | 
					        </v-col> | 
				
			||||||
 | 
					      </v-row> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    </v-container> | 
				
			||||||
 | 
					  </v-form> | 
				
			||||||
 | 
					</template> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script> | 
				
			||||||
 | 
					  import has from 'lodash/has'; | 
				
			||||||
 | 
					  import { validationMixin } from 'vuelidate'; | 
				
			||||||
 | 
					  import { required } from 'vuelidate/lib/validators'; | 
				
			||||||
 | 
					  import { mapActions } from 'vuex'; | 
				
			||||||
 | 
					  import { mapFields } from 'vuex-map-fields'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  export default { | 
				
			||||||
 | 
					    name: 'CourseForm', | 
				
			||||||
 | 
					    mixins: [validationMixin], | 
				
			||||||
 | 
					    props: { | 
				
			||||||
 | 
					      values: { | 
				
			||||||
 | 
					        type: Object, | 
				
			||||||
 | 
					        required: true | 
				
			||||||
 | 
					      }, | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      errors: { | 
				
			||||||
 | 
					        type: Object, | 
				
			||||||
 | 
					        default: () => {} | 
				
			||||||
 | 
					      }, | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      initialValues: { | 
				
			||||||
 | 
					        type: Object, | 
				
			||||||
 | 
					        default: () => {} | 
				
			||||||
 | 
					      } | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    data() { | 
				
			||||||
 | 
					      return { | 
				
			||||||
 | 
					        title: null, | 
				
			||||||
 | 
					        code: null, | 
				
			||||||
 | 
					        category: null, | 
				
			||||||
 | 
					        visibility: null, | 
				
			||||||
 | 
					      }; | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    computed: { | 
				
			||||||
 | 
					      ...mapFields('coursecategory', { | 
				
			||||||
 | 
					        categorySelectItems: 'selectItems' | 
				
			||||||
 | 
					      }), | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // eslint-disable-next-line | 
				
			||||||
 | 
					      item() { | 
				
			||||||
 | 
					        return this.initialValues || this.values; | 
				
			||||||
 | 
					      }, | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      titleErrors() { | 
				
			||||||
 | 
					        const errors = []; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!this.$v.item.title.$dirty) return errors; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        has(this.violations, 'title') && errors.push(this.violations.title); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        !this.$v.item.title.required && errors.push(this.$t('Field is required')); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return errors; | 
				
			||||||
 | 
					      }, | 
				
			||||||
 | 
					      codeErrors() { | 
				
			||||||
 | 
					        const errors = []; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!this.$v.item.code.$dirty) return errors; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        has(this.violations, 'code') && errors.push(this.violations.code); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        !this.$v.item.code.required && errors.push(this.$t('Field is required')); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return errors; | 
				
			||||||
 | 
					      }, | 
				
			||||||
 | 
					      categoryErrors() { | 
				
			||||||
 | 
					        const errors = []; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!this.$v.item.category.$dirty) return errors; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        has(this.violations, 'category') && errors.push(this.violations.category); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return errors; | 
				
			||||||
 | 
					      }, | 
				
			||||||
 | 
					      visibilityErrors() { | 
				
			||||||
 | 
					        const errors = []; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!this.$v.item.visibility.$dirty) return errors; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        has(this.violations, 'visibility') && errors.push(this.violations.visibility); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        !this.$v.item.visibility.required && errors.push(this.$t('Field is required')); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return errors; | 
				
			||||||
 | 
					      }, | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      violations() { | 
				
			||||||
 | 
					        return this.errors || {}; | 
				
			||||||
 | 
					      } | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    mounted() { | 
				
			||||||
 | 
					      this.categoryGetSelectItems(); | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    methods: { | 
				
			||||||
 | 
					      ...mapActions({ | 
				
			||||||
 | 
					        categoryGetSelectItems: 'coursecategory/fetchSelectItems' | 
				
			||||||
 | 
					      }), | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    validations: { | 
				
			||||||
 | 
					      item: { | 
				
			||||||
 | 
					        title: { | 
				
			||||||
 | 
					          required, | 
				
			||||||
 | 
					        }, | 
				
			||||||
 | 
					        code: { | 
				
			||||||
 | 
					          required, | 
				
			||||||
 | 
					        }, | 
				
			||||||
 | 
					        category: { | 
				
			||||||
 | 
					        }, | 
				
			||||||
 | 
					        visibility: { | 
				
			||||||
 | 
					          required, | 
				
			||||||
 | 
					        }, | 
				
			||||||
 | 
					      } | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  }; | 
				
			||||||
 | 
					</script> | 
				
			||||||
@ -0,0 +1,9 @@ | 
				
			|||||||
 | 
					<template> | 
				
			||||||
 | 
					  <router-view></router-view> | 
				
			||||||
 | 
					</template> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script> | 
				
			||||||
 | 
					  export default { | 
				
			||||||
 | 
					      name: 'CourseLayout' | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					</script> | 
				
			||||||
@ -0,0 +1,40 @@ | 
				
			|||||||
 | 
					<template> | 
				
			||||||
 | 
					  <v-container fluid> | 
				
			||||||
 | 
					    <v-row> | 
				
			||||||
 | 
					      <v-col cols="12" sm="6" md="6"> | 
				
			||||||
 | 
					        <v-text-field | 
				
			||||||
 | 
					                v-model="item.name" | 
				
			||||||
 | 
					                :label="$t('name')" | 
				
			||||||
 | 
					                type="text" | 
				
			||||||
 | 
					        /> | 
				
			||||||
 | 
					      </v-col> | 
				
			||||||
 | 
					    </v-row> | 
				
			||||||
 | 
					  </v-container> | 
				
			||||||
 | 
					</template> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default { | 
				
			||||||
 | 
					  name: 'CourseCategoryFilter', | 
				
			||||||
 | 
					  props: { | 
				
			||||||
 | 
					    values: { | 
				
			||||||
 | 
					      type: Object, | 
				
			||||||
 | 
					      required: true | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  data() { | 
				
			||||||
 | 
					    return {}; | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  mounted() { | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  computed: { | 
				
			||||||
 | 
					    // eslint-disable-next-line | 
				
			||||||
 | 
					    item() { | 
				
			||||||
 | 
					      return this.initialValues || this.values; | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  methods: { | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					}; | 
				
			||||||
 | 
					</script> | 
				
			||||||
@ -0,0 +1,113 @@ | 
				
			|||||||
 | 
					<template> | 
				
			||||||
 | 
					  <v-form> | 
				
			||||||
 | 
					    <v-container fluid> | 
				
			||||||
 | 
					      <v-row> | 
				
			||||||
 | 
					        <v-col cols="12" sm="6" md="6"> | 
				
			||||||
 | 
					          <v-text-field | 
				
			||||||
 | 
					                  v-model="item.name" | 
				
			||||||
 | 
					                  :error-messages="nameErrors" | 
				
			||||||
 | 
					                  :label="$t('name')" | 
				
			||||||
 | 
					                  required | 
				
			||||||
 | 
					                  @input="$v.item.name.$touch()" | 
				
			||||||
 | 
					                  @blur="$v.item.name.$touch()" | 
				
			||||||
 | 
					          /> | 
				
			||||||
 | 
					          </v-col> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <v-col cols="12" sm="6" md="6"> | 
				
			||||||
 | 
					          <v-text-field | 
				
			||||||
 | 
					                  v-model="item.code" | 
				
			||||||
 | 
					                  :error-messages="codeErrors" | 
				
			||||||
 | 
					                  :label="$t('code')" | 
				
			||||||
 | 
					                  required | 
				
			||||||
 | 
					                  @input="$v.item.code.$touch()" | 
				
			||||||
 | 
					                  @blur="$v.item.code.$touch()" | 
				
			||||||
 | 
					          /> | 
				
			||||||
 | 
					        </v-col> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      </v-row> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    </v-container> | 
				
			||||||
 | 
					  </v-form> | 
				
			||||||
 | 
					</template> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script> | 
				
			||||||
 | 
					import has from 'lodash/has'; | 
				
			||||||
 | 
					import { validationMixin } from 'vuelidate'; | 
				
			||||||
 | 
					import { required } from 'vuelidate/lib/validators'; | 
				
			||||||
 | 
					import { mapActions } from 'vuex'; | 
				
			||||||
 | 
					import { mapFields } from 'vuex-map-fields'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default { | 
				
			||||||
 | 
					  name: 'CourseCategoryForm', | 
				
			||||||
 | 
					  mixins: [validationMixin], | 
				
			||||||
 | 
					  props: { | 
				
			||||||
 | 
					    values: { | 
				
			||||||
 | 
					      type: Object, | 
				
			||||||
 | 
					      required: true | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    errors: { | 
				
			||||||
 | 
					      type: Object, | 
				
			||||||
 | 
					      default: () => {} | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    initialValues: { | 
				
			||||||
 | 
					      type: Object, | 
				
			||||||
 | 
					      default: () => {} | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  mounted() { | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  data() { | 
				
			||||||
 | 
					    return { | 
				
			||||||
 | 
					    }; | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  computed: { | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // eslint-disable-next-line | 
				
			||||||
 | 
					    item() { | 
				
			||||||
 | 
					      return this.initialValues || this.values; | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    nameErrors() { | 
				
			||||||
 | 
					      const errors = []; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (!this.$v.item.name.$dirty) return errors; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      has(this.violations, 'name') && errors.push(this.violations.name); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      !this.$v.item.name.required && errors.push(this.$t('Field is required')); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return errors; | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    codeErrors() { | 
				
			||||||
 | 
					      const errors = []; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (!this.$v.item.code.$dirty) return errors; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      has(this.violations, 'code') && errors.push(this.violations.code); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      !this.$v.item.code.required && errors.push(this.$t('Field is required')); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return errors; | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    violations() { | 
				
			||||||
 | 
					      return this.errors || {}; | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  methods: { | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  validations: { | 
				
			||||||
 | 
					    item: { | 
				
			||||||
 | 
					       name: { | 
				
			||||||
 | 
					          required, | 
				
			||||||
 | 
					        }, | 
				
			||||||
 | 
					      code: { | 
				
			||||||
 | 
					        required, | 
				
			||||||
 | 
					      }, | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					}; | 
				
			||||||
 | 
					</script> | 
				
			||||||
@ -0,0 +1,9 @@ | 
				
			|||||||
 | 
					<template> | 
				
			||||||
 | 
					  <router-view></router-view> | 
				
			||||||
 | 
					</template> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script> | 
				
			||||||
 | 
					  export default { | 
				
			||||||
 | 
					      name: 'CourseCategoryLayout' | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					</script> | 
				
			||||||
@ -0,0 +1,10 @@ | 
				
			|||||||
 | 
					export default class SubmissionError extends Error { | 
				
			||||||
 | 
					  constructor (errors) { | 
				
			||||||
 | 
					    super('Submit Validation Failed'); | 
				
			||||||
 | 
					    this.errors = errors; | 
				
			||||||
 | 
					    //Error.captureStackTrace(this, this.constructor);
 | 
				
			||||||
 | 
					    this.name = this.constructor.name; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return this; | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					} | 
				
			||||||
@ -0,0 +1,13 @@ | 
				
			|||||||
 | 
					import Vue from 'vue'; | 
				
			||||||
 | 
					import VueI18n from 'vue-i18n'; | 
				
			||||||
 | 
					import messages from './locales/en'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Vue.use(VueI18n); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default new VueI18n({ | 
				
			||||||
 | 
					    locale: process.env.VUE_APP_I18N_LOCALE || 'en', | 
				
			||||||
 | 
					    fallbackLocale: process.env.VUE_APP_I18N_FALLBACK_LOCALE || 'en', | 
				
			||||||
 | 
					    messages: { | 
				
			||||||
 | 
					        en: messages | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					}); | 
				
			||||||
@ -0,0 +1,22 @@ | 
				
			|||||||
 | 
					export default { | 
				
			||||||
 | 
					  'Submit': 'Submit', | 
				
			||||||
 | 
					  'Reset': 'Reset', | 
				
			||||||
 | 
					  'Delete': 'Delete', | 
				
			||||||
 | 
					  'Edit': 'Edit', | 
				
			||||||
 | 
					  'Are you sure you want to delete this item?': 'Are you sure you want to delete this item?', | 
				
			||||||
 | 
					  'No results': 'No results', | 
				
			||||||
 | 
					  'Close': 'Close', | 
				
			||||||
 | 
					  'Cancel': 'Cancel', | 
				
			||||||
 | 
					  'Updated': 'Updated', | 
				
			||||||
 | 
					  'Field': 'Field', | 
				
			||||||
 | 
					  'Value': 'Value', | 
				
			||||||
 | 
					  'Filters': 'Filters', | 
				
			||||||
 | 
					  'Filter': 'Filter', | 
				
			||||||
 | 
					  'Data unavailable': 'Data unavailable', | 
				
			||||||
 | 
					  'Loading...': 'Loading...', | 
				
			||||||
 | 
					  'Deleted': 'Deleted', | 
				
			||||||
 | 
					  'Please, insert a value bigger than zero!': 'Please, insert a value bigger than zero!', | 
				
			||||||
 | 
					  'Please type something': 'Please type something', | 
				
			||||||
 | 
					  'Field is required': 'Field is required', | 
				
			||||||
 | 
					  'Records per page:': 'Records per page:', | 
				
			||||||
 | 
					}; | 
				
			||||||
@ -0,0 +1,67 @@ | 
				
			|||||||
 | 
					import Vue from "vue"; | 
				
			||||||
 | 
					import App from "./App"; | 
				
			||||||
 | 
					import router from "./router"; | 
				
			||||||
 | 
					import store from "./store"; | 
				
			||||||
 | 
					import courseCategoryService from './services/coursecategory'; | 
				
			||||||
 | 
					import courseService from './services/course'; | 
				
			||||||
 | 
					import makeCrudModule from './store/modules/crud'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// import '@mdi/font/css/materialdesignicons.css'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*router.beforeEach((to, from, next) => { | 
				
			||||||
 | 
					    // hack to allow for forward slashes in path ids
 | 
				
			||||||
 | 
					    if (to.fullPath.includes('%2F')) { | 
				
			||||||
 | 
					        next(to.fullPath.replace('%2F', '/')); | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					    next(); | 
				
			||||||
 | 
					});*/ | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import vuetify from './plugins/vuetify' // path to vuetify export
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import ApolloClient from 'apollo-boost' | 
				
			||||||
 | 
					const apolloClient = new ApolloClient({ | 
				
			||||||
 | 
					    // You should use an absolute URL here
 | 
				
			||||||
 | 
					    uri: '/api/graphql/' | 
				
			||||||
 | 
					}) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import VueApollo from 'vue-apollo'; | 
				
			||||||
 | 
					Vue.use(VueApollo); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Vuelidate from 'vuelidate'; | 
				
			||||||
 | 
					import i18n from './i18n'; | 
				
			||||||
 | 
					Vue.config.productionTip = false; | 
				
			||||||
 | 
					Vue.use(Vuelidate); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const apolloProvider = new VueApollo({ | 
				
			||||||
 | 
					    defaultClient: apolloClient, | 
				
			||||||
 | 
					}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//import './quasar'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					store.registerModule( | 
				
			||||||
 | 
					    'course', | 
				
			||||||
 | 
					    makeCrudModule({ | 
				
			||||||
 | 
					        service: courseService | 
				
			||||||
 | 
					    }) | 
				
			||||||
 | 
					); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					store.registerModule( | 
				
			||||||
 | 
					    'coursecategory', | 
				
			||||||
 | 
					    makeCrudModule({ | 
				
			||||||
 | 
					        service: courseCategoryService | 
				
			||||||
 | 
					    }) | 
				
			||||||
 | 
					); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Vue.config.productionTip = false; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					new Vue({ | 
				
			||||||
 | 
					    vuetify, | 
				
			||||||
 | 
					    i18n, | 
				
			||||||
 | 
					    components: {App}, | 
				
			||||||
 | 
					    apolloProvider, | 
				
			||||||
 | 
					    data: {}, | 
				
			||||||
 | 
					    store, | 
				
			||||||
 | 
					    router, | 
				
			||||||
 | 
					    render: h => h(App) | 
				
			||||||
 | 
					}). | 
				
			||||||
 | 
					$mount("#app"); | 
				
			||||||
@ -0,0 +1,41 @@ | 
				
			|||||||
 | 
					import NotificationMixin from './NotificationMixin'; | 
				
			||||||
 | 
					import { formatDateTime } from '../utils/dates'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default { | 
				
			||||||
 | 
					  mixins: [NotificationMixin], | 
				
			||||||
 | 
					  methods: { | 
				
			||||||
 | 
					    formatDateTime, | 
				
			||||||
 | 
					    onCreated(item) { | 
				
			||||||
 | 
					      this.showMessage(`${item['@id']} created`); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      this.$router.push({ | 
				
			||||||
 | 
					        name: `${this.$options.servicePrefix}Update`, | 
				
			||||||
 | 
					        params: { id: item['@id'] } | 
				
			||||||
 | 
					      }); | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    onSendForm() { | 
				
			||||||
 | 
					      const createForm = this.$refs.createForm; | 
				
			||||||
 | 
					      createForm.$v.$touch(); | 
				
			||||||
 | 
					      if (!createForm.$v.$invalid) { | 
				
			||||||
 | 
					        this.create(createForm.$v.item.$model); | 
				
			||||||
 | 
					      } | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    resetForm() { | 
				
			||||||
 | 
					      this.$refs.createForm.$v.$reset(); | 
				
			||||||
 | 
					      this.item = {}; | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  watch: { | 
				
			||||||
 | 
					    created(created) { | 
				
			||||||
 | 
					      if (!created) { | 
				
			||||||
 | 
					        return; | 
				
			||||||
 | 
					      } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      this.onCreated(created); | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    error(message) { | 
				
			||||||
 | 
					      message && this.showError(message); | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					}; | 
				
			||||||
@ -0,0 +1,88 @@ | 
				
			|||||||
 | 
					import isEmpty from 'lodash/isEmpty'; | 
				
			||||||
 | 
					import { formatDateTime } from '../utils/dates'; | 
				
			||||||
 | 
					import NotificationMixin from './NotificationMixin'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default { | 
				
			||||||
 | 
					  mixins: [NotificationMixin], | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  data() { | 
				
			||||||
 | 
					    return { | 
				
			||||||
 | 
					      options: { | 
				
			||||||
 | 
					        sortBy: [], | 
				
			||||||
 | 
					        descending: false, | 
				
			||||||
 | 
					        page: 1, | 
				
			||||||
 | 
					        itemsPerPage: 15 | 
				
			||||||
 | 
					      }, | 
				
			||||||
 | 
					      filters: {} | 
				
			||||||
 | 
					    }; | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  watch: { | 
				
			||||||
 | 
					    deletedItem(item) { | 
				
			||||||
 | 
					      this.showMessage(`${item['@id']} deleted.`); | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    error(message) { | 
				
			||||||
 | 
					      message && this.showError(message); | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    items() { | 
				
			||||||
 | 
					      this.options.totalItems = this.totalItems; | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  methods: { | 
				
			||||||
 | 
					    onUpdateOptions(props) { | 
				
			||||||
 | 
					      const { page, itemsPerPage, sortBy, descending, totalItems } = props; | 
				
			||||||
 | 
					      let params = { | 
				
			||||||
 | 
					        ...this.filters | 
				
			||||||
 | 
					      }; | 
				
			||||||
 | 
					      if (itemsPerPage > 0) { | 
				
			||||||
 | 
					        params = { ...params, itemsPerPage, page }; | 
				
			||||||
 | 
					      } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (!isEmpty(sortBy)) { | 
				
			||||||
 | 
					        params[`order[${sortBy}]`] = descending ? 'desc' : 'asc'; | 
				
			||||||
 | 
					      } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      this.getPage(params).then(() => { | 
				
			||||||
 | 
					        this.options.sortBy = sortBy; | 
				
			||||||
 | 
					        this.options.descending = descending; | 
				
			||||||
 | 
					        this.options.itemsPerPage = itemsPerPage; | 
				
			||||||
 | 
					        this.options.totalItems = totalItems; | 
				
			||||||
 | 
					      }); | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    onSendFilter() { | 
				
			||||||
 | 
					      this.resetList = true; | 
				
			||||||
 | 
					      this.onUpdateOptions(this.options); | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    resetFilter() { | 
				
			||||||
 | 
					      this.filters = {}; | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    addHandler() { | 
				
			||||||
 | 
					      this.$router.push({ name: `${this.$options.servicePrefix}Create` }); | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    showHandler(item) { | 
				
			||||||
 | 
					      this.$router.push({ | 
				
			||||||
 | 
					        name: `${this.$options.servicePrefix}Show`, | 
				
			||||||
 | 
					        params: { id: item['@id'] } | 
				
			||||||
 | 
					      }); | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    editHandler(item) { | 
				
			||||||
 | 
					      this.$router.push({ | 
				
			||||||
 | 
					        name: `${this.$options.servicePrefix}Update`, | 
				
			||||||
 | 
					        params: { id: item['@id'] } | 
				
			||||||
 | 
					      }); | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    deleteHandler(item) { | 
				
			||||||
 | 
					      this.deleteItem(item).then(() => this.onUpdateOptions(this.options)); | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    formatDateTime | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					}; | 
				
			||||||
@ -0,0 +1,37 @@ | 
				
			|||||||
 | 
					import { mapFields } from 'vuex-map-fields'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default { | 
				
			||||||
 | 
					  computed: { | 
				
			||||||
 | 
					    ...mapFields('notifications', ['color', 'show', 'subText', 'text', 'timeout']) | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  methods: { | 
				
			||||||
 | 
					    cleanState() { | 
				
			||||||
 | 
					      setTimeout(() => { | 
				
			||||||
 | 
					        this.show = false; | 
				
			||||||
 | 
					      }, this.timeout); | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    showError(error) { | 
				
			||||||
 | 
					      this.showMessage(error, 'danger'); | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    showMessage(message, color = 'success') { | 
				
			||||||
 | 
					      this.show = true; | 
				
			||||||
 | 
					      this.color = color; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (typeof message === 'string') { | 
				
			||||||
 | 
					        this.text = message; | 
				
			||||||
 | 
					        this.cleanState(); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return; | 
				
			||||||
 | 
					      } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      this.text = message.message; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (message.response) this.subText = message.response.data.message; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      this.cleanState(); | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					}; | 
				
			||||||
@ -0,0 +1,47 @@ | 
				
			|||||||
 | 
					import NotificationMixin from './NotificationMixin'; | 
				
			||||||
 | 
					import { formatDateTime } from '../utils/dates'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default { | 
				
			||||||
 | 
					  mixins: [NotificationMixin], | 
				
			||||||
 | 
					  created() { | 
				
			||||||
 | 
					    this.retrieve(decodeURIComponent(this.$route.params.id)); | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  computed: { | 
				
			||||||
 | 
					    item() { | 
				
			||||||
 | 
					      return this.find(decodeURIComponent(this.$route.params.id)); | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  methods: { | 
				
			||||||
 | 
					    list() { | 
				
			||||||
 | 
					      this.$router | 
				
			||||||
 | 
					          .push({ name: `${this.$options.servicePrefix}List` }) | 
				
			||||||
 | 
					          .catch(() => {}); | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    del() { | 
				
			||||||
 | 
					      this.deleteItem(this.item).then(() => { | 
				
			||||||
 | 
					        this.showMessage(`${this.item['@id']} deleted.`); | 
				
			||||||
 | 
					        this.$router | 
				
			||||||
 | 
					          .push({ name: `${this.$options.servicePrefix}List` }) | 
				
			||||||
 | 
					          .catch(() => {}); | 
				
			||||||
 | 
					      }); | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    formatDateTime, | 
				
			||||||
 | 
					    editHandler() { | 
				
			||||||
 | 
					      this.$router.push({ | 
				
			||||||
 | 
					        name: `${this.$options.servicePrefix}Update`, | 
				
			||||||
 | 
					        params: { id: this.item['@id'] } | 
				
			||||||
 | 
					      }); | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  watch: { | 
				
			||||||
 | 
					    error(message) { | 
				
			||||||
 | 
					      message && this.showError(message); | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    deleteError(message) { | 
				
			||||||
 | 
					      message && this.showError(message); | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  beforeDestroy() { | 
				
			||||||
 | 
					    this.reset(); | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					}; | 
				
			||||||
@ -0,0 +1,79 @@ | 
				
			|||||||
 | 
					import NotificationMixin from './NotificationMixin'; | 
				
			||||||
 | 
					import { formatDateTime } from '../utils/dates'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default { | 
				
			||||||
 | 
					  mixins: [NotificationMixin], | 
				
			||||||
 | 
					  data() { | 
				
			||||||
 | 
					    return { | 
				
			||||||
 | 
					      item: {} | 
				
			||||||
 | 
					    }; | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  created() { | 
				
			||||||
 | 
					    this.retrieve(decodeURIComponent(this.$route.params.id)); | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  beforeDestroy() { | 
				
			||||||
 | 
					    this.reset(); | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  computed: { | 
				
			||||||
 | 
					    retrieved() { | 
				
			||||||
 | 
					      return this.find(decodeURIComponent(this.$route.params.id)); | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  methods: { | 
				
			||||||
 | 
					    del() { | 
				
			||||||
 | 
					      this.deleteItem(this.retrieved).then(() => { | 
				
			||||||
 | 
					        this.showMessage(`${this.item['@id']} deleted.`); | 
				
			||||||
 | 
					        this.$router | 
				
			||||||
 | 
					          .push({ name: `${this.$options.servicePrefix}List` }) | 
				
			||||||
 | 
					          .catch(() => {}); | 
				
			||||||
 | 
					      }); | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    formatDateTime, | 
				
			||||||
 | 
					    reset() { | 
				
			||||||
 | 
					      this.$refs.updateForm.$v.$reset(); | 
				
			||||||
 | 
					      this.updateReset(); | 
				
			||||||
 | 
					      this.delReset(); | 
				
			||||||
 | 
					      this.createReset(); | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    onSendForm() { | 
				
			||||||
 | 
					      const updateForm = this.$refs.updateForm; | 
				
			||||||
 | 
					      updateForm.$v.$touch(); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (!updateForm.$v.$invalid) { | 
				
			||||||
 | 
					        this.update(updateForm.$v.item.$model); | 
				
			||||||
 | 
					      } | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    resetForm() { | 
				
			||||||
 | 
					      this.$refs.updateForm.$v.$reset(); | 
				
			||||||
 | 
					      this.item = { ...this.retrieved }; | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  watch: { | 
				
			||||||
 | 
					    deleted(deleted) { | 
				
			||||||
 | 
					      if (!deleted) { | 
				
			||||||
 | 
					        return; | 
				
			||||||
 | 
					      } | 
				
			||||||
 | 
					      this.$router | 
				
			||||||
 | 
					        .push({ name: `${this.$options.servicePrefix}List` }) | 
				
			||||||
 | 
					        .catch(() => {}); | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    error(message) { | 
				
			||||||
 | 
					      message && this.showError(message); | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    deleteError(message) { | 
				
			||||||
 | 
					      message && this.showError(message); | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    updated(val) { | 
				
			||||||
 | 
					      this.showMessage(`${val['@id']} updated.`); | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    retrieved(val) { | 
				
			||||||
 | 
					      this.item = { ...val }; | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					}; | 
				
			||||||
@ -0,0 +1,15 @@ | 
				
			|||||||
 | 
					// src/plugins/vuetify.js
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import Vue from 'vue' | 
				
			||||||
 | 
					import Vuetify from 'vuetify' | 
				
			||||||
 | 
					import 'vuetify/dist/vuetify.min.css' | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Vue.use(Vuetify) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const opts = { | 
				
			||||||
 | 
					    icons: { | 
				
			||||||
 | 
					        iconfont: 'mdi' | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					}; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default new Vuetify(opts) | 
				
			||||||
@ -0,0 +1,5 @@ | 
				
			|||||||
 | 
					import Vue from 'vue' | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// import './styles/quasar.sass'
 | 
				
			||||||
 | 
					import '@quasar/extras/material-icons/material-icons.css' | 
				
			||||||
 | 
					import Quasar from 'quasar/dist/quasar.umd.js' | 
				
			||||||
@ -0,0 +1,28 @@ | 
				
			|||||||
 | 
					export default { | 
				
			||||||
 | 
					  path: '/courses', | 
				
			||||||
 | 
					  name: 'courses', | 
				
			||||||
 | 
					  component: () => import('../components/course/Layout'), | 
				
			||||||
 | 
					  redirect: { name: 'CourseList' }, | 
				
			||||||
 | 
					  children: [ | 
				
			||||||
 | 
					    { | 
				
			||||||
 | 
					      name: 'CourseList', | 
				
			||||||
 | 
					      path: '', | 
				
			||||||
 | 
					      component: () => import('../views/course/List') | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    { | 
				
			||||||
 | 
					      name: 'CourseCreate', | 
				
			||||||
 | 
					      path: 'new', | 
				
			||||||
 | 
					      component: () => import('../views/course/Create') | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    { | 
				
			||||||
 | 
					      name: 'CourseUpdate', | 
				
			||||||
 | 
					      path: ':id/edit', | 
				
			||||||
 | 
					      component: () => import('../views/course/Update') | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    { | 
				
			||||||
 | 
					      name: 'CourseShow', | 
				
			||||||
 | 
					      path: ':id', | 
				
			||||||
 | 
					      component: () => import('../views/course/Show') | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  ] | 
				
			||||||
 | 
					}; | 
				
			||||||
@ -0,0 +1,28 @@ | 
				
			|||||||
 | 
					export default { | 
				
			||||||
 | 
					  path: '/course_categories', | 
				
			||||||
 | 
					  name: 'course_categories', | 
				
			||||||
 | 
					  component: () => import('../components/coursecategory/Layout'), | 
				
			||||||
 | 
					  redirect: { name: 'CourseCategoryList' }, | 
				
			||||||
 | 
					  children: [ | 
				
			||||||
 | 
					    { | 
				
			||||||
 | 
					      name: 'CourseCategoryList', | 
				
			||||||
 | 
					      path: '', | 
				
			||||||
 | 
					      component: () => import('../views/coursecategory/List') | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    { | 
				
			||||||
 | 
					      name: 'CourseCategoryCreate', | 
				
			||||||
 | 
					      path: 'new', | 
				
			||||||
 | 
					      component: () => import('../views/coursecategory/Create') | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    { | 
				
			||||||
 | 
					      name: 'CourseCategoryUpdate', | 
				
			||||||
 | 
					      path: ':id/edit', | 
				
			||||||
 | 
					      component: () => import('../views/coursecategory/Update') | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    { | 
				
			||||||
 | 
					      name: 'CourseCategoryShow', | 
				
			||||||
 | 
					      path: ':id', | 
				
			||||||
 | 
					      component: () => import('../views/coursecategory/Show') | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  ] | 
				
			||||||
 | 
					}; | 
				
			||||||
@ -0,0 +1,18 @@ | 
				
			|||||||
 | 
					import Vue from "vue"; | 
				
			||||||
 | 
					import VueRouter from "vue-router"; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Vue.use(VueRouter); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import courseRoutes from './course'; | 
				
			||||||
 | 
					import coursecategoryRoutes from './coursecategory'; | 
				
			||||||
 | 
					import sessionRoutes from './../../quasar/router/session'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default new VueRouter({ | 
				
			||||||
 | 
					    mode: "history", | 
				
			||||||
 | 
					    routes: [ | 
				
			||||||
 | 
					        courseRoutes, | 
				
			||||||
 | 
					        ...sessionRoutes, | 
				
			||||||
 | 
					        coursecategoryRoutes, | 
				
			||||||
 | 
					        // { path: "*", redirect: "/home" }
 | 
				
			||||||
 | 
					    ] | 
				
			||||||
 | 
					}); | 
				
			||||||
@ -0,0 +1,24 @@ | 
				
			|||||||
 | 
					import fetch from '../utils/fetch'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default function makeService(endpoint) { | 
				
			||||||
 | 
					  return { | 
				
			||||||
 | 
					    find(id) { | 
				
			||||||
 | 
					      return fetch(`${id}`); | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    findAll(params) { | 
				
			||||||
 | 
					      return fetch(endpoint, params); | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    create(payload) { | 
				
			||||||
 | 
					      return fetch(endpoint, { method: 'POST', body: JSON.stringify(payload) }); | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    del(item) { | 
				
			||||||
 | 
					      return fetch(item['@id'], { method: 'DELETE' }); | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    update(payload) { | 
				
			||||||
 | 
					      return fetch(payload['@id'], { | 
				
			||||||
 | 
					        method: 'PUT', | 
				
			||||||
 | 
					        body: JSON.stringify(payload) | 
				
			||||||
 | 
					      }); | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  }; | 
				
			||||||
 | 
					} | 
				
			||||||
@ -0,0 +1,3 @@ | 
				
			|||||||
 | 
					import makeService from './api'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default makeService('courses'); | 
				
			||||||
@ -0,0 +1,3 @@ | 
				
			|||||||
 | 
					import makeService from './api'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default makeService('course_categories'); | 
				
			||||||
@ -0,0 +1,14 @@ | 
				
			|||||||
 | 
					import Vue from "vue"; | 
				
			||||||
 | 
					import Vuex from "vuex"; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import notifications from './modules/notifications'; | 
				
			||||||
 | 
					//import session from './../../quasar/store/modules/session/';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Vue.use(Vuex); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default new Vuex.Store({ | 
				
			||||||
 | 
					    modules: { | 
				
			||||||
 | 
					        notifications, | 
				
			||||||
 | 
					        //session,
 | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					}); | 
				
			||||||
@ -0,0 +1,273 @@ | 
				
			|||||||
 | 
					import Vue from 'vue'; | 
				
			||||||
 | 
					import { getField, updateField } from 'vuex-map-fields'; | 
				
			||||||
 | 
					import remove from 'lodash/remove'; | 
				
			||||||
 | 
					import SubmissionError from '../../error/SubmissionError'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const initialState = () => ({ | 
				
			||||||
 | 
					  allIds: [], | 
				
			||||||
 | 
					  byId: {}, | 
				
			||||||
 | 
					  created: null, | 
				
			||||||
 | 
					  deleted: null, | 
				
			||||||
 | 
					  error: "", | 
				
			||||||
 | 
					  isLoading: false, | 
				
			||||||
 | 
					  resetList: false, | 
				
			||||||
 | 
					  selectItems: null, | 
				
			||||||
 | 
					  totalItems: 0, | 
				
			||||||
 | 
					  updated: null, | 
				
			||||||
 | 
					  view: null, | 
				
			||||||
 | 
					  violations: null | 
				
			||||||
 | 
					}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const handleError = (commit, e) => { | 
				
			||||||
 | 
					  commit(ACTIONS.TOGGLE_LOADING); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (e instanceof SubmissionError) { | 
				
			||||||
 | 
					    commit(ACTIONS.SET_VIOLATIONS, e.errors); | 
				
			||||||
 | 
					    // eslint-disable-next-line
 | 
				
			||||||
 | 
					    commit(ACTIONS.SET_ERROR, e.errors._error); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return Promise.reject(e); | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // eslint-disable-next-line
 | 
				
			||||||
 | 
					  commit(ACTIONS.SET_ERROR, e.message); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return Promise.reject(e); | 
				
			||||||
 | 
					}; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const ACTIONS = { | 
				
			||||||
 | 
					  ADD: 'ADD', | 
				
			||||||
 | 
					  RESET_CREATE: 'RESET_CREATE', | 
				
			||||||
 | 
					  RESET_DELETE: 'RESET_DELETE', | 
				
			||||||
 | 
					  RESET_LIST: 'RESET_LIST', | 
				
			||||||
 | 
					  RESET_SHOW: 'RESET_SHOW', | 
				
			||||||
 | 
					  RESET_UPDATE: 'RESET_UPDATE', | 
				
			||||||
 | 
					  SET_CREATED: 'SET_CREATED', | 
				
			||||||
 | 
					  SET_DELETED: 'SET_DELETED', | 
				
			||||||
 | 
					  SET_ERROR: 'SET_ERROR', | 
				
			||||||
 | 
					  SET_SELECT_ITEMS: 'SET_SELECT_ITEMS', | 
				
			||||||
 | 
					  SET_TOTAL_ITEMS: 'SET_TOTAL_ITEMS', | 
				
			||||||
 | 
					  SET_UPDATED: 'SET_UPDATED', | 
				
			||||||
 | 
					  SET_VIEW: 'SET_VIEW', | 
				
			||||||
 | 
					  SET_VIOLATIONS: 'SET_VIOLATIONS', | 
				
			||||||
 | 
					  TOGGLE_LOADING: 'TOGGLE_LOADING' | 
				
			||||||
 | 
					}; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default function makeCrudModule({ | 
				
			||||||
 | 
					  normalizeRelations = x => x, | 
				
			||||||
 | 
					  resolveRelations = x => x, | 
				
			||||||
 | 
					  service | 
				
			||||||
 | 
					} = {}) { | 
				
			||||||
 | 
					  return { | 
				
			||||||
 | 
					    actions: { | 
				
			||||||
 | 
					      create: ({ commit }, values) => { | 
				
			||||||
 | 
					        commit(ACTIONS.SET_ERROR, ''); | 
				
			||||||
 | 
					        commit(ACTIONS.TOGGLE_LOADING); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        service | 
				
			||||||
 | 
					          .create(values) | 
				
			||||||
 | 
					          .then(response => response.json()) | 
				
			||||||
 | 
					          .then(data => { | 
				
			||||||
 | 
					            commit(ACTIONS.TOGGLE_LOADING); | 
				
			||||||
 | 
					            commit(ACTIONS.ADD, data); | 
				
			||||||
 | 
					            commit(ACTIONS.SET_CREATED, data); | 
				
			||||||
 | 
					          }) | 
				
			||||||
 | 
					          .catch(e => handleError(commit, e)); | 
				
			||||||
 | 
					      }, | 
				
			||||||
 | 
					      del: ({ commit }, item) => { | 
				
			||||||
 | 
					        commit(ACTIONS.TOGGLE_LOADING); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        service | 
				
			||||||
 | 
					          .del(item) | 
				
			||||||
 | 
					          .then(() => { | 
				
			||||||
 | 
					            commit(ACTIONS.TOGGLE_LOADING); | 
				
			||||||
 | 
					            commit(ACTIONS.SET_DELETED, item); | 
				
			||||||
 | 
					          }) | 
				
			||||||
 | 
					          .catch(e => handleError(commit, e)); | 
				
			||||||
 | 
					      }, | 
				
			||||||
 | 
					      fetchAll: ({ commit, state }, params) => { | 
				
			||||||
 | 
					        if (!service) throw new Error('No service specified!'); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        commit(ACTIONS.TOGGLE_LOADING); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        service | 
				
			||||||
 | 
					          .findAll({ params }) | 
				
			||||||
 | 
					          .then(response => response.json()) | 
				
			||||||
 | 
					          .then(retrieved => { | 
				
			||||||
 | 
					            commit(ACTIONS.TOGGLE_LOADING); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            commit( | 
				
			||||||
 | 
					              ACTIONS.SET_TOTAL_ITEMS, | 
				
			||||||
 | 
					              retrieved['hydra:totalItems'] | 
				
			||||||
 | 
					            ); | 
				
			||||||
 | 
					            commit(ACTIONS.SET_VIEW, retrieved['hydra:view']); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (true === state.resetList) { | 
				
			||||||
 | 
					              commit(ACTIONS.RESET_LIST); | 
				
			||||||
 | 
					            } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            retrieved['hydra:member'].forEach(item => { | 
				
			||||||
 | 
					              commit(ACTIONS.ADD, normalizeRelations(item)); | 
				
			||||||
 | 
					            }); | 
				
			||||||
 | 
					          }) | 
				
			||||||
 | 
					          .catch(e => handleError(commit, e)); | 
				
			||||||
 | 
					      }, | 
				
			||||||
 | 
					      fetchSelectItems: ( | 
				
			||||||
 | 
					        { commit }, | 
				
			||||||
 | 
					        { params = { properties: ['@id', 'name'] } } = {} | 
				
			||||||
 | 
					      ) => { | 
				
			||||||
 | 
					        commit(ACTIONS.TOGGLE_LOADING); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!service) throw new Error('No service specified!'); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        service | 
				
			||||||
 | 
					          .findAll({ params }) | 
				
			||||||
 | 
					          .then(response => response.json()) | 
				
			||||||
 | 
					          .then(retrieved => { | 
				
			||||||
 | 
					            commit( | 
				
			||||||
 | 
					              ACTIONS.SET_SELECT_ITEMS, | 
				
			||||||
 | 
					              retrieved['hydra:member'] | 
				
			||||||
 | 
					            ); | 
				
			||||||
 | 
					          }) | 
				
			||||||
 | 
					          .catch(e => handleError(commit, e)); | 
				
			||||||
 | 
					      }, | 
				
			||||||
 | 
					      load: ({ commit }, id) => { | 
				
			||||||
 | 
					        if (!service) throw new Error('No service specified!'); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        commit(ACTIONS.TOGGLE_LOADING); | 
				
			||||||
 | 
					        service | 
				
			||||||
 | 
					          .find(id) | 
				
			||||||
 | 
					          .then(response => response.json()) | 
				
			||||||
 | 
					          .then(item => { | 
				
			||||||
 | 
					            commit(ACTIONS.TOGGLE_LOADING); | 
				
			||||||
 | 
					            commit(ACTIONS.ADD, normalizeRelations(item)); | 
				
			||||||
 | 
					          }) | 
				
			||||||
 | 
					          .catch(e => handleError(commit, e)); | 
				
			||||||
 | 
					      }, | 
				
			||||||
 | 
					      resetCreate: ({ commit }) => { | 
				
			||||||
 | 
					        commit(ACTIONS.RESET_CREATE); | 
				
			||||||
 | 
					      }, | 
				
			||||||
 | 
					      resetDelete: ({ commit }) => { | 
				
			||||||
 | 
					        commit(ACTIONS.RESET_DELETE); | 
				
			||||||
 | 
					      }, | 
				
			||||||
 | 
					      resetShow: ({ commit }) => { | 
				
			||||||
 | 
					        commit(ACTIONS.RESET_SHOW); | 
				
			||||||
 | 
					      }, | 
				
			||||||
 | 
					      resetUpdate: ({ commit }) => { | 
				
			||||||
 | 
					        commit(ACTIONS.RESET_UPDATE); | 
				
			||||||
 | 
					      }, | 
				
			||||||
 | 
					      update: ({ commit }, item) => { | 
				
			||||||
 | 
					        commit(ACTIONS.SET_ERROR, ''); | 
				
			||||||
 | 
					        commit(ACTIONS.TOGGLE_LOADING); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        service | 
				
			||||||
 | 
					          .update(item) | 
				
			||||||
 | 
					          .then(response => response.json()) | 
				
			||||||
 | 
					          .then(data => { | 
				
			||||||
 | 
					            commit(ACTIONS.TOGGLE_LOADING); | 
				
			||||||
 | 
					            commit(ACTIONS.SET_UPDATED, data); | 
				
			||||||
 | 
					          }) | 
				
			||||||
 | 
					          .catch(e => handleError(commit, e)); | 
				
			||||||
 | 
					      } | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    getters: { | 
				
			||||||
 | 
					      find: state => id => { | 
				
			||||||
 | 
					        return resolveRelations(state.byId[id]); | 
				
			||||||
 | 
					      }, | 
				
			||||||
 | 
					      getField, | 
				
			||||||
 | 
					      list: (state, getters) => { | 
				
			||||||
 | 
					        return state.allIds.map(id => getters.find(id)); | 
				
			||||||
 | 
					      } | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    mutations: { | 
				
			||||||
 | 
					      updateField, | 
				
			||||||
 | 
					      [ACTIONS.ADD]: (state, item) => { | 
				
			||||||
 | 
					        Vue.set(state.byId, item['@id'], item); | 
				
			||||||
 | 
					        Vue.set(state, 'isLoading', false); | 
				
			||||||
 | 
					        if (state.allIds.includes(item['@id'])) return; | 
				
			||||||
 | 
					        state.allIds.push(item['@id']); | 
				
			||||||
 | 
					      }, | 
				
			||||||
 | 
					      [ACTIONS.RESET_CREATE]: state => { | 
				
			||||||
 | 
					        Object.assign(state, { | 
				
			||||||
 | 
					          isLoading: false, | 
				
			||||||
 | 
					          error: '', | 
				
			||||||
 | 
					          created: null, | 
				
			||||||
 | 
					          violations: null | 
				
			||||||
 | 
					        }); | 
				
			||||||
 | 
					      }, | 
				
			||||||
 | 
					      [ACTIONS.RESET_DELETE]: state => { | 
				
			||||||
 | 
					        Object.assign(state, { | 
				
			||||||
 | 
					          isLoading: false, | 
				
			||||||
 | 
					          error: '', | 
				
			||||||
 | 
					          deleted: null | 
				
			||||||
 | 
					        }); | 
				
			||||||
 | 
					      }, | 
				
			||||||
 | 
					      [ACTIONS.RESET_LIST]: state => { | 
				
			||||||
 | 
					        Object.assign(state, { | 
				
			||||||
 | 
					          allIds: [], | 
				
			||||||
 | 
					          byId: {}, | 
				
			||||||
 | 
					          error: '', | 
				
			||||||
 | 
					          isLoading: false, | 
				
			||||||
 | 
					          resetList: false | 
				
			||||||
 | 
					        }); | 
				
			||||||
 | 
					      }, | 
				
			||||||
 | 
					      [ACTIONS.RESET_SHOW]: state => { | 
				
			||||||
 | 
					        Object.assign(state, { | 
				
			||||||
 | 
					          error: '', | 
				
			||||||
 | 
					          isLoading: false | 
				
			||||||
 | 
					        }); | 
				
			||||||
 | 
					      }, | 
				
			||||||
 | 
					      [ACTIONS.RESET_UPDATE]: state => { | 
				
			||||||
 | 
					        Object.assign(state, { | 
				
			||||||
 | 
					          error: '', | 
				
			||||||
 | 
					          isLoading: false, | 
				
			||||||
 | 
					          updated: null, | 
				
			||||||
 | 
					          violations: null | 
				
			||||||
 | 
					        }); | 
				
			||||||
 | 
					      }, | 
				
			||||||
 | 
					      [ACTIONS.SET_CREATED]: (state, created) => { | 
				
			||||||
 | 
					        Object.assign(state, { created }); | 
				
			||||||
 | 
					      }, | 
				
			||||||
 | 
					      [ACTIONS.SET_DELETED]: (state, deleted) => { | 
				
			||||||
 | 
					        if (!state.allIds.includes(deleted['@id'])) return; | 
				
			||||||
 | 
					        Object.assign(state, { | 
				
			||||||
 | 
					          allIds: remove(state.allIds, item => item['@id'] === deleted['@id']), | 
				
			||||||
 | 
					          byId: remove(state.byId, id => id === deleted['@id']), | 
				
			||||||
 | 
					          deleted | 
				
			||||||
 | 
					        }); | 
				
			||||||
 | 
					      }, | 
				
			||||||
 | 
					      [ACTIONS.SET_ERROR]: (state, error) => { | 
				
			||||||
 | 
					        Object.assign(state, { error, isLoading: false }); | 
				
			||||||
 | 
					      }, | 
				
			||||||
 | 
					      [ACTIONS.SET_SELECT_ITEMS]: (state, selectItems) => { | 
				
			||||||
 | 
					        Object.assign(state, { | 
				
			||||||
 | 
					          error: '', | 
				
			||||||
 | 
					          isLoading: false, | 
				
			||||||
 | 
					          selectItems | 
				
			||||||
 | 
					        }); | 
				
			||||||
 | 
					      }, | 
				
			||||||
 | 
					      [ACTIONS.SET_TOTAL_ITEMS]: (state, totalItems) => { | 
				
			||||||
 | 
					        Object.assign(state, { totalItems }); | 
				
			||||||
 | 
					      }, | 
				
			||||||
 | 
					      [ACTIONS.SET_UPDATED]: (state, updated) => { | 
				
			||||||
 | 
					        Object.assign(state, { | 
				
			||||||
 | 
					          byId: { | 
				
			||||||
 | 
					            [updated['@id']]: updated | 
				
			||||||
 | 
					          }, | 
				
			||||||
 | 
					          updated | 
				
			||||||
 | 
					        }); | 
				
			||||||
 | 
					      }, | 
				
			||||||
 | 
					      [ACTIONS.SET_VIEW]: (state, view) => { | 
				
			||||||
 | 
					        Object.assign(state, { view }); | 
				
			||||||
 | 
					      }, | 
				
			||||||
 | 
					      [ACTIONS.SET_VIOLATIONS]: (state, violations) => { | 
				
			||||||
 | 
					        Object.assign(state, { violations }); | 
				
			||||||
 | 
					      }, | 
				
			||||||
 | 
					      [ACTIONS.TOGGLE_LOADING]: state => { | 
				
			||||||
 | 
					        Object.assign(state, { error: '', isLoading: !state.isLoading }); | 
				
			||||||
 | 
					      } | 
				
			||||||
 | 
					    }, | 
				
			||||||
 | 
					    namespaced: true, | 
				
			||||||
 | 
					    state: initialState | 
				
			||||||
 | 
					  }; | 
				
			||||||
 | 
					} | 
				
			||||||
@ -0,0 +1,18 @@ | 
				
			|||||||
 | 
					import {getField, updateField} from 'vuex-map-fields'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default { | 
				
			||||||
 | 
					  namespaced: true, | 
				
			||||||
 | 
					  state: { | 
				
			||||||
 | 
					    show: false, | 
				
			||||||
 | 
					    color: 'error', | 
				
			||||||
 | 
					    text: 'An error occurred', | 
				
			||||||
 | 
					    subText: '', | 
				
			||||||
 | 
					    timeout: 6000 | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  getters: { | 
				
			||||||
 | 
					    getField | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  mutations: { | 
				
			||||||
 | 
					    updateField | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					}; | 
				
			||||||
@ -0,0 +1,9 @@ | 
				
			|||||||
 | 
					import moment from 'moment'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const formatDateTime = function(date) { | 
				
			||||||
 | 
					  if (!date) return null; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return moment(date).format('DD/MM/YYYY'); | 
				
			||||||
 | 
					}; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export { formatDateTime }; | 
				
			||||||
@ -0,0 +1,71 @@ | 
				
			|||||||
 | 
					import isObject from 'lodash/isObject'; | 
				
			||||||
 | 
					import { ENTRYPOINT } from '../config/entrypoint'; | 
				
			||||||
 | 
					import SubmissionError from '../error/SubmissionError'; | 
				
			||||||
 | 
					import { normalize } from './hydra'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const MIME_TYPE = 'application/ld+json'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const makeParamArray = (key, arr) => | 
				
			||||||
 | 
					  arr.map(val => `${key}[]=${val}`).join('&'); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default function(id, options = {}) { | 
				
			||||||
 | 
					  if ('undefined' === typeof options.headers) options.headers = new Headers(); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (null === options.headers.get('Accept')) | 
				
			||||||
 | 
					    options.headers.set('Accept', MIME_TYPE); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if ( | 
				
			||||||
 | 
					    'undefined' !== options.body && | 
				
			||||||
 | 
					    !(options.body instanceof FormData) && | 
				
			||||||
 | 
					    null === options.headers.get('Content-Type') | 
				
			||||||
 | 
					  ) | 
				
			||||||
 | 
					    options.headers.set('Content-Type', MIME_TYPE); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (options.params) { | 
				
			||||||
 | 
					    const params = normalize(options.params); | 
				
			||||||
 | 
					    let queryString = Object.keys(params) | 
				
			||||||
 | 
					      .map(key => | 
				
			||||||
 | 
					        Array.isArray(params[key]) | 
				
			||||||
 | 
					          ? makeParamArray(key, params[key]) | 
				
			||||||
 | 
					          : `${key}=${params[key]}` | 
				
			||||||
 | 
					      ) | 
				
			||||||
 | 
					      .join('&'); | 
				
			||||||
 | 
					    id = `${id}?${queryString}`; | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const entryPoint = ENTRYPOINT + (ENTRYPOINT.endsWith('/') ? '' : '/'); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const payload = options.body && JSON.parse(options.body); | 
				
			||||||
 | 
					  if (isObject(payload) && payload['@id']) | 
				
			||||||
 | 
					    options.body = JSON.stringify(normalize(payload)); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //console.log(id); console.log(new URL(id, entryPoint));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return global.fetch(new URL(id, entryPoint), options).then(response => { | 
				
			||||||
 | 
					    if (response.ok) return response; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return response.json().then( | 
				
			||||||
 | 
					      json => { | 
				
			||||||
 | 
					        const error = | 
				
			||||||
 | 
					          json['hydra:description'] || | 
				
			||||||
 | 
					          json['hydra:title'] || | 
				
			||||||
 | 
					          'An error occurred.'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!json.violations) throw Error(error); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let errors = { _error: error }; | 
				
			||||||
 | 
					        json.violations.forEach(violation => | 
				
			||||||
 | 
					          errors[violation.propertyPath] | 
				
			||||||
 | 
					            ? (errors[violation.propertyPath] += | 
				
			||||||
 | 
					            '\n' + errors[violation.propertyPath]) | 
				
			||||||
 | 
					            : (errors[violation.propertyPath] = violation.message) | 
				
			||||||
 | 
					        ); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        throw new SubmissionError(errors); | 
				
			||||||
 | 
					      }, | 
				
			||||||
 | 
					      () => { | 
				
			||||||
 | 
					        throw new Error(response.statusText || 'An error occurred.'); | 
				
			||||||
 | 
					      } | 
				
			||||||
 | 
					    ); | 
				
			||||||
 | 
					  }); | 
				
			||||||
 | 
					} | 
				
			||||||
@ -0,0 +1,19 @@ | 
				
			|||||||
 | 
					import get from 'lodash/get'; | 
				
			||||||
 | 
					import has from 'lodash/has'; | 
				
			||||||
 | 
					import mapValues from 'lodash/mapValues'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function normalize(data) { | 
				
			||||||
 | 
					  if (has(data, 'hydra:member')) { | 
				
			||||||
 | 
					    // Normalize items in collections
 | 
				
			||||||
 | 
					    data['hydra:member'] = data['hydra:member'].map(item => normalize(item)); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return data; | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Flatten nested documents
 | 
				
			||||||
 | 
					  return mapValues(data, value => | 
				
			||||||
 | 
					    Array.isArray(value) | 
				
			||||||
 | 
					      ? value.map(v => get(v, '@id', v)) | 
				
			||||||
 | 
					      : get(value, '@id', value) | 
				
			||||||
 | 
					  ); | 
				
			||||||
 | 
					} | 
				
			||||||
@ -0,0 +1,7 @@ | 
				
			|||||||
 | 
					import moment from 'moment'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const date = function(value) { | 
				
			||||||
 | 
					  return moment(value).isValid(); | 
				
			||||||
 | 
					}; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export { date }; | 
				
			||||||
@ -0,0 +1,46 @@ | 
				
			|||||||
 | 
					<template> | 
				
			||||||
 | 
					  <div> | 
				
			||||||
 | 
					    <CourseForm ref="createForm" :values="item" :errors="violations" /> | 
				
			||||||
 | 
					    <Loading :visible="isLoading" /> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <Toolbar :handle-submit="onSendForm" :handle-reset="resetForm"></Toolbar> | 
				
			||||||
 | 
					  </div> | 
				
			||||||
 | 
					</template> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script> | 
				
			||||||
 | 
					import { mapActions } from 'vuex'; | 
				
			||||||
 | 
					import { createHelpers } from 'vuex-map-fields'; | 
				
			||||||
 | 
					import CourseForm from '../../components/course/Form'; | 
				
			||||||
 | 
					import Loading from '../../components/Loading'; | 
				
			||||||
 | 
					import Toolbar from '../../components/Toolbar'; | 
				
			||||||
 | 
					import CreateMixin from '../../mixins/CreateMixin'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const servicePrefix = 'Course'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const { mapFields } = createHelpers({ | 
				
			||||||
 | 
					  getterType: 'course/getField', | 
				
			||||||
 | 
					  mutationType: 'course/updateField' | 
				
			||||||
 | 
					}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default { | 
				
			||||||
 | 
					  name: 'CourseCreate', | 
				
			||||||
 | 
					  servicePrefix, | 
				
			||||||
 | 
					  mixins: [CreateMixin], | 
				
			||||||
 | 
					  components: { | 
				
			||||||
 | 
					    Loading, | 
				
			||||||
 | 
					    Toolbar, | 
				
			||||||
 | 
					    CourseForm | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  data() { | 
				
			||||||
 | 
					    return { | 
				
			||||||
 | 
					      item: {} | 
				
			||||||
 | 
					    }; | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  computed: { | 
				
			||||||
 | 
					    ...mapFields(['error', 'isLoading', 'created', 'violations']) | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  methods: { | 
				
			||||||
 | 
					    ...mapActions('course', ['create', 'reset']) | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					}; | 
				
			||||||
 | 
					</script> | 
				
			||||||
@ -0,0 +1,122 @@ | 
				
			|||||||
 | 
					<template> | 
				
			||||||
 | 
					  <div class="course-list"> | 
				
			||||||
 | 
					    <Toolbar :handle-add="addHandler" /> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <v-container grid-list-xl fluid> | 
				
			||||||
 | 
					      <v-layout row wrap> | 
				
			||||||
 | 
					<!--        <v-flex sm12>--> | 
				
			||||||
 | 
					<!--          <h1>Course List</h1>--> | 
				
			||||||
 | 
					<!--        </v-flex>--> | 
				
			||||||
 | 
					        <v-flex lg12> | 
				
			||||||
 | 
					          <DataFilter :handle-filter="onSendFilter" :handle-reset="resetFilter"> | 
				
			||||||
 | 
					            <CourseFilterForm | 
				
			||||||
 | 
					              ref="filterForm" | 
				
			||||||
 | 
					              :values="filters" | 
				
			||||||
 | 
					              slot="filter" | 
				
			||||||
 | 
					            /> | 
				
			||||||
 | 
					          </DataFilter> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <br /> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <v-data-table | 
				
			||||||
 | 
					            v-model="selected" | 
				
			||||||
 | 
					            :headers="headers" | 
				
			||||||
 | 
					            :items="items" | 
				
			||||||
 | 
					            :items-per-page.sync="options.itemsPerPage" | 
				
			||||||
 | 
					            :loading="isLoading" | 
				
			||||||
 | 
					            :loading-text="$t('Loading...')" | 
				
			||||||
 | 
					            :options.sync="options" | 
				
			||||||
 | 
					            :server-items-length="totalItems" | 
				
			||||||
 | 
					            class="elevation-1" | 
				
			||||||
 | 
					            item-key="@id" | 
				
			||||||
 | 
					            show-select | 
				
			||||||
 | 
					            @update:options="onUpdateOptions" | 
				
			||||||
 | 
					          > | 
				
			||||||
 | 
					            <template slot="item.category" slot-scope="{ item }"> | 
				
			||||||
 | 
					              <div v-if="item['category']"> | 
				
			||||||
 | 
					                {{ item['category'].name }} | 
				
			||||||
 | 
					              </div> | 
				
			||||||
 | 
					              <div v-else> | 
				
			||||||
 | 
					                - | 
				
			||||||
 | 
					              </div> | 
				
			||||||
 | 
					            </template> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <template slot="item.visibility" slot-scope="{ item }"> | 
				
			||||||
 | 
					              {{ $n(item['visibility']) }} | 
				
			||||||
 | 
					            </template> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <template slot="item.expirationDate" slot-scope="{ item }"> | 
				
			||||||
 | 
					              {{ formatDateTime(item['expirationDate'], 'long') }} | 
				
			||||||
 | 
					            </template> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <ActionCell | 
				
			||||||
 | 
					              slot="item.action" | 
				
			||||||
 | 
					              slot-scope="props" | 
				
			||||||
 | 
					              :handle-show="() => showHandler(props.item)" | 
				
			||||||
 | 
					              :handle-edit="() => editHandler(props.item)" | 
				
			||||||
 | 
					              :handle-delete="() => deleteHandler(props.item)" | 
				
			||||||
 | 
					            ></ActionCell> | 
				
			||||||
 | 
					          </v-data-table> | 
				
			||||||
 | 
					        </v-flex> | 
				
			||||||
 | 
					      </v-layout> | 
				
			||||||
 | 
					    </v-container> | 
				
			||||||
 | 
					  </div> | 
				
			||||||
 | 
					</template> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script> | 
				
			||||||
 | 
					import { mapActions, mapGetters } from 'vuex'; | 
				
			||||||
 | 
					import { mapFields } from 'vuex-map-fields'; | 
				
			||||||
 | 
					import ListMixin from '../../mixins/ListMixin'; | 
				
			||||||
 | 
					import ActionCell from '../../components/ActionCell'; | 
				
			||||||
 | 
					import CourseFilterForm from '../../components/course/Filter'; | 
				
			||||||
 | 
					import DataFilter from '../../components/DataFilter'; | 
				
			||||||
 | 
					import Toolbar from '../../components/Toolbar'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default { | 
				
			||||||
 | 
					  name: 'CourseList', | 
				
			||||||
 | 
					  servicePrefix: 'Course', | 
				
			||||||
 | 
					  mixins: [ListMixin], | 
				
			||||||
 | 
					  components: { | 
				
			||||||
 | 
					    Toolbar, | 
				
			||||||
 | 
					    ActionCell, | 
				
			||||||
 | 
					    CourseFilterForm, | 
				
			||||||
 | 
					    DataFilter | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  data() { | 
				
			||||||
 | 
					    return { | 
				
			||||||
 | 
					      headers: [ | 
				
			||||||
 | 
					        { text: 'title', value: 'title' }, | 
				
			||||||
 | 
					        { text: 'code', value: 'code' }, | 
				
			||||||
 | 
					        { text: 'courseLanguage', value: 'Language' }, | 
				
			||||||
 | 
					        { text: 'category', value: 'category' }, | 
				
			||||||
 | 
					        { text: 'visibility', value: 'visibility' }, | 
				
			||||||
 | 
					        { | 
				
			||||||
 | 
					          text: 'Actions', | 
				
			||||||
 | 
					          value: 'action', | 
				
			||||||
 | 
					          sortable: false | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					      ], | 
				
			||||||
 | 
					      selected: [] | 
				
			||||||
 | 
					    }; | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  computed: { | 
				
			||||||
 | 
					    ...mapGetters('course', { | 
				
			||||||
 | 
					      items: 'list' | 
				
			||||||
 | 
					    }), | 
				
			||||||
 | 
					    ...mapFields('course', { | 
				
			||||||
 | 
					      deletedItem: 'deleted', | 
				
			||||||
 | 
					      error: 'error', | 
				
			||||||
 | 
					      isLoading: 'isLoading', | 
				
			||||||
 | 
					      resetList: 'resetList', | 
				
			||||||
 | 
					      totalItems: 'totalItems', | 
				
			||||||
 | 
					      view: 'view' | 
				
			||||||
 | 
					    }) | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  methods: { | 
				
			||||||
 | 
					    ...mapActions('course', { | 
				
			||||||
 | 
					      getPage: 'fetchAll', | 
				
			||||||
 | 
					      deleteItem: 'del' | 
				
			||||||
 | 
					    }) | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					}; | 
				
			||||||
 | 
					</script> | 
				
			||||||
@ -0,0 +1,119 @@ | 
				
			|||||||
 | 
					<template> | 
				
			||||||
 | 
					  <div> | 
				
			||||||
 | 
					    <Toolbar | 
				
			||||||
 | 
					            :handle-delete="del" | 
				
			||||||
 | 
					            :handle-list="list" | 
				
			||||||
 | 
					    > | 
				
			||||||
 | 
					      <template slot="left"> | 
				
			||||||
 | 
					        <v-toolbar-title v-if="item">{{ | 
				
			||||||
 | 
					          `${$options.servicePrefix} ${item['@id']}` | 
				
			||||||
 | 
					        }}</v-toolbar-title> | 
				
			||||||
 | 
					      </template> | 
				
			||||||
 | 
					    </Toolbar> | 
				
			||||||
 | 
					    <br /> | 
				
			||||||
 | 
					    <div v-if="item" class="table-course-show"> | 
				
			||||||
 | 
					      <v-simple-table> | 
				
			||||||
 | 
					        <template slot="default"> | 
				
			||||||
 | 
					          <thead> | 
				
			||||||
 | 
					            <tr> | 
				
			||||||
 | 
					              <th>Field</th> | 
				
			||||||
 | 
					              <th>Value</th> | 
				
			||||||
 | 
					              <th>Field</th> | 
				
			||||||
 | 
					              <th>Value</th> | 
				
			||||||
 | 
					            </tr> | 
				
			||||||
 | 
					          </thead> | 
				
			||||||
 | 
					          <tbody> | 
				
			||||||
 | 
					            <tr> | 
				
			||||||
 | 
					              <td><strong>{{ $t('title') }}</strong></td> | 
				
			||||||
 | 
					              <td> | 
				
			||||||
 | 
					                                    {{ item['title'] }} | 
				
			||||||
 | 
					              </td> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              <td><strong>{{ $t('code') }}</strong></td> | 
				
			||||||
 | 
					              <td> | 
				
			||||||
 | 
					                                    {{ item['code'] }} | 
				
			||||||
 | 
					              </td> | 
				
			||||||
 | 
					            </tr> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <tr> | 
				
			||||||
 | 
					              <td><strong>{{ $t('courseLanguage') }}</strong></td> | 
				
			||||||
 | 
					              <td> | 
				
			||||||
 | 
					                                    {{ item['courseLanguage'] }} | 
				
			||||||
 | 
					              </td> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              <td><strong>{{ $t('category') }}</strong></td> | 
				
			||||||
 | 
					              <td> | 
				
			||||||
 | 
					                <div v-if="item['category']"> | 
				
			||||||
 | 
					                  {{ item['category'].name }} | 
				
			||||||
 | 
					                </div> | 
				
			||||||
 | 
					                <div v-else> | 
				
			||||||
 | 
					                  - | 
				
			||||||
 | 
					                </div> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              </td> | 
				
			||||||
 | 
					            </tr> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <tr> | 
				
			||||||
 | 
					              <td><strong>{{ $t('visibility') }}</strong></td> | 
				
			||||||
 | 
					              <td> | 
				
			||||||
 | 
					                {{ $n(item['visibility']) }}              </td> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              <td><strong>{{ $t('departmentName') }}</strong></td> | 
				
			||||||
 | 
					              <td> | 
				
			||||||
 | 
					                                    {{ item['departmentName'] }} | 
				
			||||||
 | 
					              </td> | 
				
			||||||
 | 
					            </tr> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <tr> | 
				
			||||||
 | 
					              <td><strong>{{ $t('departmentUrl') }}</strong></td> | 
				
			||||||
 | 
					              <td> | 
				
			||||||
 | 
					                                    {{ item['departmentUrl'] }} | 
				
			||||||
 | 
					              </td> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              <td><strong>{{ $t('expirationDate') }}</strong></td> | 
				
			||||||
 | 
					              <td> | 
				
			||||||
 | 
					                {{ formatDateTime(item['expirationDate'], 'long') }}              </td> | 
				
			||||||
 | 
					            </tr> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          </tbody> | 
				
			||||||
 | 
					        </template> | 
				
			||||||
 | 
					      </v-simple-table> | 
				
			||||||
 | 
					    </div> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <Loading :visible="isLoading" /> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  </div> | 
				
			||||||
 | 
					</template> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script> | 
				
			||||||
 | 
					import { mapActions, mapGetters } from 'vuex'; | 
				
			||||||
 | 
					import { mapFields } from 'vuex-map-fields'; | 
				
			||||||
 | 
					import Loading from '../../components/Loading'; | 
				
			||||||
 | 
					import ShowMixin from '../../mixins/ShowMixin'; | 
				
			||||||
 | 
					import Toolbar from '../../components/Toolbar'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const servicePrefix = 'Course'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default { | 
				
			||||||
 | 
					  name: 'CourseShow', | 
				
			||||||
 | 
					  servicePrefix, | 
				
			||||||
 | 
					  components: { | 
				
			||||||
 | 
					      Loading, | 
				
			||||||
 | 
					      Toolbar | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  mixins: [ShowMixin], | 
				
			||||||
 | 
					  computed: { | 
				
			||||||
 | 
					    ...mapFields('course', { | 
				
			||||||
 | 
					      isLoading: 'isLoading' | 
				
			||||||
 | 
					    }), | 
				
			||||||
 | 
					    ...mapGetters('course', ['find']) | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  methods: { | 
				
			||||||
 | 
					    ...mapActions('course', { | 
				
			||||||
 | 
					      deleteItem: 'del', | 
				
			||||||
 | 
					      reset: 'resetShow', | 
				
			||||||
 | 
					      retrieve: 'load' | 
				
			||||||
 | 
					    }) | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					}; | 
				
			||||||
 | 
					</script> | 
				
			||||||
@ -0,0 +1,67 @@ | 
				
			|||||||
 | 
					<template> | 
				
			||||||
 | 
					  <div> | 
				
			||||||
 | 
					    <v-card | 
				
			||||||
 | 
					        class="mx-auto" | 
				
			||||||
 | 
					    > | 
				
			||||||
 | 
					    <CourseForm | 
				
			||||||
 | 
					      ref="updateForm" | 
				
			||||||
 | 
					      v-if="item" | 
				
			||||||
 | 
					      :values="item" | 
				
			||||||
 | 
					      :errors="violations" | 
				
			||||||
 | 
					    /> | 
				
			||||||
 | 
					    <Loading :visible="isLoading || deleteLoading" /> | 
				
			||||||
 | 
					      <v-footer> | 
				
			||||||
 | 
					        <Toolbar | 
				
			||||||
 | 
					                :handle-submit="onSendForm" | 
				
			||||||
 | 
					                :handle-reset="resetForm" | 
				
			||||||
 | 
					                :handle-delete="del" | 
				
			||||||
 | 
					        /> | 
				
			||||||
 | 
					      </v-footer> | 
				
			||||||
 | 
					    </v-card> | 
				
			||||||
 | 
					  </div> | 
				
			||||||
 | 
					</template> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script> | 
				
			||||||
 | 
					import { mapActions, mapGetters } from 'vuex'; | 
				
			||||||
 | 
					import { mapFields } from 'vuex-map-fields'; | 
				
			||||||
 | 
					import CourseForm from '../../components/course/Form.vue'; | 
				
			||||||
 | 
					import Loading from '../../components/Loading'; | 
				
			||||||
 | 
					import Toolbar from '../../components/Toolbar'; | 
				
			||||||
 | 
					import UpdateMixin from '../../mixins/UpdateMixin'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const servicePrefix = 'Course'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default { | 
				
			||||||
 | 
					  name: 'CourseUpdate', | 
				
			||||||
 | 
					  servicePrefix, | 
				
			||||||
 | 
					  mixins: [UpdateMixin], | 
				
			||||||
 | 
					  components: { | 
				
			||||||
 | 
					    Loading, | 
				
			||||||
 | 
					    Toolbar, | 
				
			||||||
 | 
					    CourseForm | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  computed: { | 
				
			||||||
 | 
					    ...mapFields('course', { | 
				
			||||||
 | 
					      deleteLoading: 'isLoading', | 
				
			||||||
 | 
					      isLoading: 'isLoading', | 
				
			||||||
 | 
					      error: 'error', | 
				
			||||||
 | 
					      updated: 'updated', | 
				
			||||||
 | 
					      violations: 'violations' | 
				
			||||||
 | 
					    }), | 
				
			||||||
 | 
					    ...mapGetters('course', ['find']) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  methods: { | 
				
			||||||
 | 
					    ...mapActions('course', { | 
				
			||||||
 | 
					      createReset: 'resetCreate', | 
				
			||||||
 | 
					      deleteItem: 'del', | 
				
			||||||
 | 
					      delReset: 'resetDelete', | 
				
			||||||
 | 
					      retrieve: 'load', | 
				
			||||||
 | 
					      update: 'update', | 
				
			||||||
 | 
					      updateReset: 'resetUpdate' | 
				
			||||||
 | 
					    }) | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					}; | 
				
			||||||
 | 
					</script> | 
				
			||||||
@ -0,0 +1,45 @@ | 
				
			|||||||
 | 
					<template> | 
				
			||||||
 | 
					  <div> | 
				
			||||||
 | 
					    <Toolbar :handle-submit="onSendForm" :handle-reset="resetForm"></Toolbar> | 
				
			||||||
 | 
					    <CourseCategoryForm ref="createForm" :values="item" :errors="violations" /> | 
				
			||||||
 | 
					    <Loading :visible="isLoading" /> | 
				
			||||||
 | 
					  </div> | 
				
			||||||
 | 
					</template> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script> | 
				
			||||||
 | 
					import { mapActions } from 'vuex'; | 
				
			||||||
 | 
					import { createHelpers } from 'vuex-map-fields'; | 
				
			||||||
 | 
					import CourseCategoryForm from '../../components/coursecategory/Form'; | 
				
			||||||
 | 
					import Loading from '../../components/Loading'; | 
				
			||||||
 | 
					import Toolbar from '../../components/Toolbar'; | 
				
			||||||
 | 
					import CreateMixin from '../../mixins/CreateMixin'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const servicePrefix = 'CourseCategory'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const { mapFields } = createHelpers({ | 
				
			||||||
 | 
					  getterType: 'coursecategory/getField', | 
				
			||||||
 | 
					  mutationType: 'coursecategory/updateField' | 
				
			||||||
 | 
					}); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default { | 
				
			||||||
 | 
					  name: 'CourseCategoryCreate', | 
				
			||||||
 | 
					  servicePrefix, | 
				
			||||||
 | 
					  mixins: [CreateMixin], | 
				
			||||||
 | 
					  components: { | 
				
			||||||
 | 
					    Loading, | 
				
			||||||
 | 
					    Toolbar, | 
				
			||||||
 | 
					    CourseCategoryForm | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  data() { | 
				
			||||||
 | 
					    return { | 
				
			||||||
 | 
					      item: {} | 
				
			||||||
 | 
					    }; | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  computed: { | 
				
			||||||
 | 
					    ...mapFields(['error', 'isLoading', 'created', 'violations']) | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  methods: { | 
				
			||||||
 | 
					    ...mapActions('coursecategory', ['create', 'reset']) | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					}; | 
				
			||||||
 | 
					</script> | 
				
			||||||
@ -0,0 +1,104 @@ | 
				
			|||||||
 | 
					<template> | 
				
			||||||
 | 
					  <div class="coursecategory-list"> | 
				
			||||||
 | 
					    <Toolbar :handle-add="addHandler" /> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <v-container grid-list-xl fluid> | 
				
			||||||
 | 
					      <v-layout row wrap> | 
				
			||||||
 | 
					        <v-flex sm12> | 
				
			||||||
 | 
					          <h1>CourseCategory List</h1> | 
				
			||||||
 | 
					        </v-flex> | 
				
			||||||
 | 
					        <v-flex lg12> | 
				
			||||||
 | 
					          <DataFilter :handle-filter="onSendFilter" :handle-reset="resetFilter"> | 
				
			||||||
 | 
					            <CourseCategoryFilterForm | 
				
			||||||
 | 
					              ref="filterForm" | 
				
			||||||
 | 
					              :values="filters" | 
				
			||||||
 | 
					              slot="filter" | 
				
			||||||
 | 
					            /> | 
				
			||||||
 | 
					          </DataFilter> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <br /> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <v-data-table | 
				
			||||||
 | 
					            v-model="selected" | 
				
			||||||
 | 
					            :headers="headers" | 
				
			||||||
 | 
					            :items="items" | 
				
			||||||
 | 
					            :items-per-page.sync="options.itemsPerPage" | 
				
			||||||
 | 
					            :loading="isLoading" | 
				
			||||||
 | 
					            :loading-text="$t('Loading...')" | 
				
			||||||
 | 
					            :options.sync="options" | 
				
			||||||
 | 
					            :server-items-length="totalItems" | 
				
			||||||
 | 
					            class="elevation-1" | 
				
			||||||
 | 
					            item-key="@id" | 
				
			||||||
 | 
					            show-select | 
				
			||||||
 | 
					            @update:options="onUpdateOptions" | 
				
			||||||
 | 
					          > | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <ActionCell | 
				
			||||||
 | 
					              slot="item.action" | 
				
			||||||
 | 
					              slot-scope="props" | 
				
			||||||
 | 
					              :handle-show="() => showHandler(props.item)" | 
				
			||||||
 | 
					              :handle-edit="() => editHandler(props.item)" | 
				
			||||||
 | 
					              :handle-delete="() => deleteHandler(props.item)" | 
				
			||||||
 | 
					            ></ActionCell> | 
				
			||||||
 | 
					          </v-data-table> | 
				
			||||||
 | 
					        </v-flex> | 
				
			||||||
 | 
					      </v-layout> | 
				
			||||||
 | 
					    </v-container> | 
				
			||||||
 | 
					  </div> | 
				
			||||||
 | 
					</template> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script> | 
				
			||||||
 | 
					import { mapActions, mapGetters } from 'vuex'; | 
				
			||||||
 | 
					import { mapFields } from 'vuex-map-fields'; | 
				
			||||||
 | 
					import ListMixin from '../../mixins/ListMixin'; | 
				
			||||||
 | 
					import ActionCell from '../../components/ActionCell'; | 
				
			||||||
 | 
					import CourseCategoryFilterForm from '../../components/coursecategory/Filter'; | 
				
			||||||
 | 
					import DataFilter from '../../components/DataFilter'; | 
				
			||||||
 | 
					import Toolbar from '../../components/Toolbar'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default { | 
				
			||||||
 | 
					  name: 'CourseCategoryList', | 
				
			||||||
 | 
					  servicePrefix: 'CourseCategory', | 
				
			||||||
 | 
					  mixins: [ListMixin], | 
				
			||||||
 | 
					  components: { | 
				
			||||||
 | 
					    Toolbar, | 
				
			||||||
 | 
					    ActionCell, | 
				
			||||||
 | 
					    CourseCategoryFilterForm, | 
				
			||||||
 | 
					    DataFilter | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  data() { | 
				
			||||||
 | 
					    return { | 
				
			||||||
 | 
					      headers: [ | 
				
			||||||
 | 
					        { text: 'name', value: 'name' }, | 
				
			||||||
 | 
					        { text: 'code', value: 'code' }, | 
				
			||||||
 | 
					        //{ text: 'description', value: 'description' }, | 
				
			||||||
 | 
					        { | 
				
			||||||
 | 
					          text: 'Actions', | 
				
			||||||
 | 
					          value: 'action', | 
				
			||||||
 | 
					          sortable: false | 
				
			||||||
 | 
					        } | 
				
			||||||
 | 
					      ], | 
				
			||||||
 | 
					      selected: [] | 
				
			||||||
 | 
					    }; | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  computed: { | 
				
			||||||
 | 
					    ...mapGetters('coursecategory', { | 
				
			||||||
 | 
					      items: 'list' | 
				
			||||||
 | 
					    }), | 
				
			||||||
 | 
					    ...mapFields('coursecategory', { | 
				
			||||||
 | 
					      deletedItem: 'deleted', | 
				
			||||||
 | 
					      error: 'error', | 
				
			||||||
 | 
					      isLoading: 'isLoading', | 
				
			||||||
 | 
					      resetList: 'resetList', | 
				
			||||||
 | 
					      totalItems: 'totalItems', | 
				
			||||||
 | 
					      view: 'view' | 
				
			||||||
 | 
					    }) | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  methods: { | 
				
			||||||
 | 
					    ...mapActions('coursecategory', { | 
				
			||||||
 | 
					      getPage: 'fetchAll', | 
				
			||||||
 | 
					      deleteItem: 'del' | 
				
			||||||
 | 
					    }) | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					}; | 
				
			||||||
 | 
					</script> | 
				
			||||||
@ -0,0 +1,87 @@ | 
				
			|||||||
 | 
					<template> | 
				
			||||||
 | 
					  <div> | 
				
			||||||
 | 
					    <Toolbar :handle-edit="editHandler"  :handle-delete="del"> | 
				
			||||||
 | 
					      <template slot="left"> | 
				
			||||||
 | 
					        <v-toolbar-title v-if="item">{{ | 
				
			||||||
 | 
					          `${$options.servicePrefix} ${item['@id']}` | 
				
			||||||
 | 
					        }}</v-toolbar-title> | 
				
			||||||
 | 
					      </template> | 
				
			||||||
 | 
					    </Toolbar> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <br /> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div v-if="item" class="table-coursecategory-show"> | 
				
			||||||
 | 
					      <v-simple-table> | 
				
			||||||
 | 
					        <template slot="default"> | 
				
			||||||
 | 
					          <thead> | 
				
			||||||
 | 
					            <tr> | 
				
			||||||
 | 
					              <th>Field</th> | 
				
			||||||
 | 
					              <th>Value</th> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              <th>Field</th> | 
				
			||||||
 | 
					              <th>Value</th> | 
				
			||||||
 | 
					            </tr> | 
				
			||||||
 | 
					          </thead> | 
				
			||||||
 | 
					          <tbody> | 
				
			||||||
 | 
					            <tr> | 
				
			||||||
 | 
					              <td><strong>{{ $t('name') }}</strong></td> | 
				
			||||||
 | 
					              <td> | 
				
			||||||
 | 
					                                    {{ item['name'] }} | 
				
			||||||
 | 
					              </td> | 
				
			||||||
 | 
					             | 
				
			||||||
 | 
					              <td><strong>{{ $t('code') }}</strong></td> | 
				
			||||||
 | 
					              <td> | 
				
			||||||
 | 
					                                    {{ item['code'] }} | 
				
			||||||
 | 
					              </td> | 
				
			||||||
 | 
					            </tr> | 
				
			||||||
 | 
					             | 
				
			||||||
 | 
					            <tr> | 
				
			||||||
 | 
					              <td><strong>{{ $t('description') }}</strong></td> | 
				
			||||||
 | 
					              <td> | 
				
			||||||
 | 
					                                    {{ item['description'] }} | 
				
			||||||
 | 
					              </td> | 
				
			||||||
 | 
					             | 
				
			||||||
 | 
					              <td></td> | 
				
			||||||
 | 
					            </tr> | 
				
			||||||
 | 
					             | 
				
			||||||
 | 
					          </tbody> | 
				
			||||||
 | 
					        </template> | 
				
			||||||
 | 
					      </v-simple-table> | 
				
			||||||
 | 
					    </div> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <Loading :visible="isLoading" /> | 
				
			||||||
 | 
					  </div> | 
				
			||||||
 | 
					</template> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script> | 
				
			||||||
 | 
					import { mapActions, mapGetters } from 'vuex'; | 
				
			||||||
 | 
					import { mapFields } from 'vuex-map-fields'; | 
				
			||||||
 | 
					import Loading from '../../components/Loading'; | 
				
			||||||
 | 
					import ShowMixin from '../../mixins/ShowMixin'; | 
				
			||||||
 | 
					import Toolbar from '../../components/Toolbar'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const servicePrefix = 'CourseCategory'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default { | 
				
			||||||
 | 
					  name: 'CourseCategoryShow', | 
				
			||||||
 | 
					  servicePrefix, | 
				
			||||||
 | 
					  components: { | 
				
			||||||
 | 
					      Loading, | 
				
			||||||
 | 
					      Toolbar | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  mixins: [ShowMixin], | 
				
			||||||
 | 
					  computed: { | 
				
			||||||
 | 
					    ...mapFields('coursecategory', { | 
				
			||||||
 | 
					      isLoading: 'isLoading' | 
				
			||||||
 | 
					    }), | 
				
			||||||
 | 
					    ...mapGetters('coursecategory', ['find']) | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  methods: { | 
				
			||||||
 | 
					    ...mapActions('coursecategory', { | 
				
			||||||
 | 
					      deleteItem: 'del', | 
				
			||||||
 | 
					      reset: 'resetShow', | 
				
			||||||
 | 
					      retrieve: 'load' | 
				
			||||||
 | 
					    }) | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					}; | 
				
			||||||
 | 
					</script> | 
				
			||||||
@ -0,0 +1,61 @@ | 
				
			|||||||
 | 
					<template> | 
				
			||||||
 | 
					  <div> | 
				
			||||||
 | 
					    <Toolbar | 
				
			||||||
 | 
					      :handle-submit="onSendForm" | 
				
			||||||
 | 
					      :handle-reset="resetForm" | 
				
			||||||
 | 
					      :handle-delete="del" | 
				
			||||||
 | 
					    /> | 
				
			||||||
 | 
					    <CourseCategoryForm | 
				
			||||||
 | 
					      ref="updateForm" | 
				
			||||||
 | 
					      v-if="item" | 
				
			||||||
 | 
					      :values="item" | 
				
			||||||
 | 
					      :errors="violations" | 
				
			||||||
 | 
					    /> | 
				
			||||||
 | 
					    <Loading :visible="isLoading || deleteLoading" /> | 
				
			||||||
 | 
					  </div> | 
				
			||||||
 | 
					</template> | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script> | 
				
			||||||
 | 
					import { mapActions, mapGetters } from 'vuex'; | 
				
			||||||
 | 
					import { mapFields } from 'vuex-map-fields'; | 
				
			||||||
 | 
					import CourseCategoryForm from '../../components/coursecategory/Form.vue'; | 
				
			||||||
 | 
					import Loading from '../../components/Loading'; | 
				
			||||||
 | 
					import Toolbar from '../../components/Toolbar'; | 
				
			||||||
 | 
					import UpdateMixin from '../../mixins/UpdateMixin'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const servicePrefix = 'CourseCategory'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default { | 
				
			||||||
 | 
					  name: 'CourseCategoryUpdate', | 
				
			||||||
 | 
					  servicePrefix, | 
				
			||||||
 | 
					  mixins: [UpdateMixin], | 
				
			||||||
 | 
					  components: { | 
				
			||||||
 | 
					    Loading, | 
				
			||||||
 | 
					    Toolbar, | 
				
			||||||
 | 
					    CourseCategoryForm | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  computed: { | 
				
			||||||
 | 
					    ...mapFields('coursecategory', { | 
				
			||||||
 | 
					      deleteLoading: 'isLoading', | 
				
			||||||
 | 
					      isLoading: 'isLoading', | 
				
			||||||
 | 
					      error: 'error', | 
				
			||||||
 | 
					      updated: 'updated', | 
				
			||||||
 | 
					      violations: 'violations' | 
				
			||||||
 | 
					    }), | 
				
			||||||
 | 
					    ...mapGetters('coursecategory', ['find']) | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  methods: { | 
				
			||||||
 | 
					    ...mapActions('coursecategory', { | 
				
			||||||
 | 
					      createReset: 'resetCreate', | 
				
			||||||
 | 
					      deleteItem: 'del', | 
				
			||||||
 | 
					      delReset: 'resetDelete', | 
				
			||||||
 | 
					      retrieve: 'load', | 
				
			||||||
 | 
					      update: 'update', | 
				
			||||||
 | 
					      updateReset: 'resetUpdate' | 
				
			||||||
 | 
					    }) | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					}; | 
				
			||||||
 | 
					</script> | 
				
			||||||
@ -0,0 +1,11 @@ | 
				
			|||||||
 | 
					module.exports = { | 
				
			||||||
 | 
					  pluginOptions: { | 
				
			||||||
 | 
					    quasar: { | 
				
			||||||
 | 
					      importStrategy: 'manual', | 
				
			||||||
 | 
					      rtlSupport: false | 
				
			||||||
 | 
					    } | 
				
			||||||
 | 
					  }, | 
				
			||||||
 | 
					  transpileDependencies: [ | 
				
			||||||
 | 
					    'quasar' | 
				
			||||||
 | 
					  ] | 
				
			||||||
 | 
					} | 
				
			||||||
					Loading…
					
					
				
		Reference in new issue