diff --git a/backend/module/eCampApi/src/eCampApi/V1/Rpc/Auth/AuthController.php b/backend/module/eCampApi/src/eCampApi/V1/Rpc/Auth/AuthController.php index 9420b76b68..190ea42920 100644 --- a/backend/module/eCampApi/src/eCampApi/V1/Rpc/Auth/AuthController.php +++ b/backend/module/eCampApi/src/eCampApi/V1/Rpc/Auth/AuthController.php @@ -57,9 +57,11 @@ public function indexAction() { } if ($user != null) { $data['user'] = $user->getDisplayName(); + $data['username'] = $user->getUsername(); $data['role'] = $user->getRole(); } else { $data['user'] = 'guest'; + $data['username'] = 'guest'; $data['role'] = 'guest'; } diff --git a/backend/module/eCampApi/src/eCampApi/V1/Rpc/Index/IndexController.php b/backend/module/eCampApi/src/eCampApi/V1/Rpc/Index/IndexController.php index 3eb6d4a8d8..81ed10cbce 100644 --- a/backend/module/eCampApi/src/eCampApi/V1/Rpc/Index/IndexController.php +++ b/backend/module/eCampApi/src/eCampApi/V1/Rpc/Index/IndexController.php @@ -37,6 +37,14 @@ public function indexAction() { } if ($user != null) { $data['user'] = $user->getDisplayName(); + + $data['profile'] = Link::factory([ + 'rel' => 'profile', + 'route' => [ + 'name' => 'e-camp-api.rest.doctrine.user', + 'params' => [ 'user_id' => $userId ] + ] + ]); } else { $data['user'] = 'guest'; } diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 54ffcb5e3c..382af10d56 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -1,25 +1,132 @@ - - - + + + + + + + - - + + + + + + + eCamp v0.1.0 + + diff --git a/frontend/src/components/base/BackButton.vue b/frontend/src/components/base/BackButton.vue new file mode 100644 index 0000000000..e2c171b480 --- /dev/null +++ b/frontend/src/components/base/BackButton.vue @@ -0,0 +1,16 @@ + + + mdi-arrow-left + + + + + + diff --git a/frontend/src/components/base/ButtonAdd.vue b/frontend/src/components/base/ButtonAdd.vue index 671b5f896f..0f886add08 100644 --- a/frontend/src/components/base/ButtonAdd.vue +++ b/frontend/src/components/base/ButtonAdd.vue @@ -1,9 +1,10 @@ - mdi-plus + {{ icon }} Add @@ -12,7 +13,10 @@ diff --git a/frontend/src/components/base/ButtonDelete.vue b/frontend/src/components/base/ButtonDelete.vue index f8dfc7fbe9..d4ae58538e 100644 --- a/frontend/src/components/base/ButtonDelete.vue +++ b/frontend/src/components/base/ButtonDelete.vue @@ -1,9 +1,10 @@ - mdi-delete + {{ icon }} Delete @@ -12,7 +13,10 @@ diff --git a/frontend/src/components/base/ButtonEdit.vue b/frontend/src/components/base/ButtonEdit.vue index 4b2499fa66..58b40ba690 100644 --- a/frontend/src/components/base/ButtonEdit.vue +++ b/frontend/src/components/base/ButtonEdit.vue @@ -1,9 +1,9 @@ - mdi-pencil + {{ icon }} Edit @@ -12,7 +12,10 @@ diff --git a/frontend/src/components/base/ContentCard.vue b/frontend/src/components/base/ContentCard.vue index e5f4893be2..049bfca2a7 100644 --- a/frontend/src/components/base/ContentCard.vue +++ b/frontend/src/components/base/ContentCard.vue @@ -3,18 +3,15 @@ Displays the content wrapped inside a card. --> - - - - {{ icon }} - - + + + + {{ icon }} {{ title }} - - - - - + + + + @@ -22,15 +19,14 @@ Displays the content wrapped inside a card. export default { name: 'ContentCard', props: { - icon: { type: String, required: true }, - title: { type: String, required: true } - }, - data () { - return { - } + loaded: { type: Boolean, required: false, default: true }, + title: { type: String, required: false, default: '' }, + icon: { type: String, required: false, default: '' }, + maxWidth: { type: String, default: '' } } } diff --git a/frontend/src/components/base/ContentGroup.vue b/frontend/src/components/base/ContentGroup.vue new file mode 100644 index 0000000000..5ed4b4fb3d --- /dev/null +++ b/frontend/src/components/base/ContentGroup.vue @@ -0,0 +1,34 @@ + + + + + + + {{ icon }} + {{ title }} + + + + + + + + + + diff --git a/frontend/src/components/base/Logo.vue b/frontend/src/components/base/Logo.vue new file mode 100644 index 0000000000..e471835c65 --- /dev/null +++ b/frontend/src/components/base/Logo.vue @@ -0,0 +1,32 @@ + + + + + 🏕️eCamp + + + + + + + + + diff --git a/frontend/src/components/base/MobileSearch.vue b/frontend/src/components/base/MobileSearch.vue new file mode 100644 index 0000000000..006423e91b --- /dev/null +++ b/frontend/src/components/base/MobileSearch.vue @@ -0,0 +1,52 @@ + + + + + mdi-chevron-left + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/components/base/NavDesktopSearch.vue b/frontend/src/components/base/NavDesktopSearch.vue new file mode 100644 index 0000000000..566421cbe9 --- /dev/null +++ b/frontend/src/components/base/NavDesktopSearch.vue @@ -0,0 +1,27 @@ + + + + + + + + + diff --git a/frontend/src/components/base/NavDesktopUserMenu.vue b/frontend/src/components/base/NavDesktopUserMenu.vue new file mode 100644 index 0000000000..c96e7b28e0 --- /dev/null +++ b/frontend/src/components/base/NavDesktopUserMenu.vue @@ -0,0 +1,69 @@ + + + + + + + {{ username }} + + mdi-account + + + + + + mdi-account + Profil + + + mdi-format-list-bulleted-triangle + Meine Camps + + + {{ logoutIcon }} + + Log out + + + + + + + + diff --git a/frontend/src/components/base/SideBar.vue b/frontend/src/components/base/SideBar.vue new file mode 100644 index 0000000000..473e8deba3 --- /dev/null +++ b/frontend/src/components/base/SideBar.vue @@ -0,0 +1,44 @@ + + + + mdi-format-list-bulleted-triangle + + + + mdi-chevron-left + + + + + + + + + + + diff --git a/frontend/src/components/camp/ApiDemo.vue b/frontend/src/components/camp/ApiDemo.vue index 64a16bf177..7d7ebc8a8a 100644 --- a/frontend/src/components/camp/ApiDemo.vue +++ b/frontend/src/components/camp/ApiDemo.vue @@ -3,20 +3,22 @@ Displays details on a single camp and allows to edit them. --> - + + class="my-4" /> @@ -50,6 +55,7 @@ Displays details on a single camp and allows to edit them. fieldname="color" label="Color Example" readonly + class="mb-4" required /> @@ -60,19 +66,18 @@ Displays details on a single camp and allows to edit them. {{ period.description }} {{ period.start }} - {{ period.end }} - - + - + diff --git a/frontend/src/components/camp/CampSettings.vue b/frontend/src/components/camp/CampSettings.vue index 947bc46ade..d7494a251c 100644 --- a/frontend/src/components/camp/CampSettings.vue +++ b/frontend/src/components/camp/CampSettings.vue @@ -3,14 +3,16 @@ Displays details on a single camp and allows to edit them. --> - + + class="my-4" /> - + + + diff --git a/frontend/src/components/camp/Collaborators.vue b/frontend/src/components/camp/Collaborators.vue deleted file mode 100644 index 46d922d5a4..0000000000 --- a/frontend/src/components/camp/Collaborators.vue +++ /dev/null @@ -1,293 +0,0 @@ - - - - - - mdi-account-group - - Mitarbeiter - - - - - - - User - - - Rolle - - - Option - - - - - - - - {{ collaborator.user().username }} - - - - - - - - mdi-close - - delete - - - - - - - - - - - Offene Anfragen - - - - - User - - - Rolle - - - Option - - - - {{ collaborator.user().username }} - - - - - - - mdi-check - - accept - - - - mdi-close - - deny - - - - - - - - - - Offene Einladungen - - - - - - User - - - Rolle - - - Option - - - - - - {{ collaborator.user().username }} - - - - - - - mdi-close - - delete - - - - - - - - - - Einladen - - - - - - - {{ result.username }} - - - - mdi-plus-circle - - member - - - - - mdi-plus-circle - - manager - - - - - - - - diff --git a/frontend/src/components/camp/EventList.vue b/frontend/src/components/camp/EventList.vue new file mode 100644 index 0000000000..e5efbd05ae --- /dev/null +++ b/frontend/src/components/camp/EventList.vue @@ -0,0 +1,44 @@ + + + + + + + + {{ eventInstance.event().event_category().short }} + + {{ eventInstance.event().title }} + {{ eventInstance.start_time }} - {{ eventInstance.end_time }} + + + + + + + diff --git a/frontend/src/components/camp/Periods.vue b/frontend/src/components/camp/Periods.vue deleted file mode 100644 index 3a0be17d33..0000000000 --- a/frontend/src/components/camp/Periods.vue +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - - {{ period.description }} - - {{ period.start }} - {{ period.end }} - - - - - - - {{ eventInstance.event().event_category().short }} - - {{ eventInstance.event().title }} - {{ eventInstance.start_time }} - {{ eventInstance.end_time }} - - - - - - - - - - diff --git a/frontend/src/components/Picasso.vue b/frontend/src/components/camp/Picasso.vue similarity index 71% rename from frontend/src/components/Picasso.vue rename to frontend/src/components/camp/Picasso.vue index 05561c4cce..e0af5ea80d 100644 --- a/frontend/src/components/Picasso.vue +++ b/frontend/src/components/camp/Picasso.vue @@ -3,25 +3,27 @@ Listing all given event instances in a calendar view. --> - + - + + diff --git a/frontend/src/components/form/__tests__/ApiTextField.spec.js b/frontend/src/components/form/__tests__/ApiTextField.spec.js index 71687492e1..04011fa101 100644 --- a/frontend/src/components/form/__tests__/ApiTextField.spec.js +++ b/frontend/src/components/form/__tests__/ApiTextField.spec.js @@ -62,9 +62,6 @@ describe('ApiTextField.vue', () => { expect(patchSpy).toBeCalledTimes(1) expect(patchSpy).toBeCalledWith(config.propsData.uri, { [config.propsData.fieldname]: newValue }) - const statusIcon = wrapper.find({ name: 'StatusIcon' }).vm - // expect(statusIcon.status).toBe('saving') - // wait for patch Promise to resolve await flushPromises() diff --git a/frontend/src/components/form/__tests__/__snapshots__/ApiSelect.spec.js.snap b/frontend/src/components/form/__tests__/__snapshots__/ApiSelect.spec.js.snap index 071e193a30..36a53acef8 100644 --- a/frontend/src/components/form/__tests__/__snapshots__/ApiSelect.spec.js.snap +++ b/frontend/src/components/form/__tests__/__snapshots__/ApiSelect.spec.js.snap @@ -2,7 +2,7 @@ exports[`ApiTextField.vue renders correctly 1`] = ` diff --git a/frontend/src/components/form/__tests__/__snapshots__/ApiTextField.spec.js.snap b/frontend/src/components/form/__tests__/__snapshots__/ApiTextField.spec.js.snap index ce2323ae3c..493ca2f915 100644 --- a/frontend/src/components/form/__tests__/__snapshots__/ApiTextField.spec.js.snap +++ b/frontend/src/components/form/__tests__/__snapshots__/ApiTextField.spec.js.snap @@ -2,7 +2,7 @@ exports[`ApiTextField.vue renders correctly 1`] = ` - - - - - mdi-format-list-bulleted-triangle - - - mdi-chevron-left - - - - - - - - - - ⛺ - - - - - - - {{ data.item.title }} - - - - - - - mdi-calendar-text - Events - - - mdi-calendar-month - Picasso - - - mdi-account-group - Team - - - mdi-information - Admin - - - - - {{ logoutIcon }} - - Log out - - - mdi-login - Log in - - - mdi-account - - - - - - - - - - - - - {{ camp().name }} - mdi-tent - - - Events - mdi-calendar-text - - - Picasso - mdi-calendar-month - - - Team - mdi-account-group - - - Profile - mdi-account - - - - - - eCamp v0.0.1 - - - - - - - diff --git a/frontend/src/layouts/DefaultLayout.vue b/frontend/src/layouts/DefaultLayout.vue deleted file mode 100644 index a9ac222ada..0000000000 --- a/frontend/src/layouts/DefaultLayout.vue +++ /dev/null @@ -1,180 +0,0 @@ - - - - - - mdi-format-list-bulleted-triangle - - - - mdi-chevron-left - - - - - - - - - - - 🏕️ eCamp - - - - Home - - - Camps - - - - - {{ logoutIcon }} - - Log out - - - mdi-login - Log in - - - mdi-account - - - - - - - - - - - - - Home - mdi-home - - - Camps - mdi-format-list-bulleted-triangle - - - Profile - mdi-account - - - - - - eCamp v0.0.1 - - - - - - - diff --git a/frontend/src/layouts/EmptyLayout.vue b/frontend/src/layouts/EmptyLayout.vue deleted file mode 100644 index 5a5cd921eb..0000000000 --- a/frontend/src/layouts/EmptyLayout.vue +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - diff --git a/frontend/src/main.js b/frontend/src/main.js index 119a09a13d..86f549a443 100644 --- a/frontend/src/main.js +++ b/frontend/src/main.js @@ -5,9 +5,13 @@ import router from '@/router' import store from './store' import vuetify from './plugins/vuetify' -Vue.component('empty-layout', () => import('./layouts/EmptyLayout')) -Vue.component('default-layout', () => import('./layouts/DefaultLayout')) -Vue.component('camp-layout', () => import('./layouts/CampLayout')) +Vue.filter('loading', function (value, loadingState, isLoading = v => typeof v === 'function' && v.loading) { + if (typeof value === 'function' && !value.loading) { + // Wrap the function that is passed into the | loading filter + return (v, ...args) => isLoading(v) ? loadingState : value(v, ...args) + } + return isLoading(value) ? loadingState : value +}) new Vue({ router, diff --git a/frontend/src/mixins/apiPropsMixin.js b/frontend/src/mixins/apiPropsMixin.js index 8d6c2c86ad..d4ee77173f 100644 --- a/frontend/src/mixins/apiPropsMixin.js +++ b/frontend/src/mixins/apiPropsMixin.js @@ -20,7 +20,10 @@ export const apiPropsMixin = { autoSaveDelay: { type: Number, default: 800, required: false }, /* Validation criteria */ - required: { type: Boolean, default: false, required: false } + required: { type: Boolean, default: false, required: false }, + + /* Removes the margin (for inline fields) */ + noMargin: { type: Boolean, default: false, required: false } } } diff --git a/frontend/src/router.js b/frontend/src/router.js index 2200e9262e..0f65566d48 100644 --- a/frontend/src/router.js +++ b/frontend/src/router.js @@ -5,6 +5,7 @@ import { refreshLoginStatus } from '@/auth' Vue.use(Router) +/* istanbul ignore next */ export default new Router({ mode: 'history', base: process.env.BASE_URL, @@ -12,86 +13,110 @@ export default new Router({ { path: '/register', name: 'register', - meta: { layout: 'empty' }, - component: () => import(/* webpackChunkName: "register" */ './views/auth/Register.vue') + components: { + topbar: () => import(/* webpackChunkName: "navigation" */ './views/auth/NavDesktop'), + default: () => import(/* webpackChunkName: "register" */ './views/auth/Register') + } }, { path: '/register-done', name: 'register-done', - meta: { layout: 'empty' }, - component: () => import(/* webpackChunkName: "register" */ './views/auth/RegisterDone.vue') + components: { + topbar: () => import(/* webpackChunkName: "navigation" */ './views/auth/NavDesktop'), + default: () => import(/* webpackChunkName: "register" */ './views/auth/RegisterDone') + } }, { path: '/login', name: 'login', - meta: { layout: 'empty' }, - component: () => import(/* webpackChunkName: "login" */ './views/auth/Login.vue') + components: { + topbar: () => import(/* webpackChunkName: "navigation" */ './views/auth/NavDesktop'), + default: () => import(/* webpackChunkName: "login" */ './views/auth/Login') + } }, { path: '/loginCallback', name: 'loginCallback', - component: () => import(/* webpackChunkName: "login" */ './views/auth/LoginCallback.vue') + components: { + topbar: () => import(/* webpackChunkName: "navigation" */ './views/auth/NavDesktop'), + default: () => import(/* webpackChunkName: "login" */ './views/auth/LoginCallback') + } }, { path: '/', name: 'home', - component: () => import(/* webpackChunkName: "about" */ './views/Home.vue'), + components: { + topbar: () => import(/* webpackChunkName: "navigation" */ './views/NavDesktop'), + default: () => import(/* webpackChunkName: "about" */ './views/Home'), + bottombar: () => import(/* webpackChunkName: "navigation" */ './views/NavMobile') + }, + beforeEnter: requireAuth + }, + { + path: '/profile', + name: 'profile', + components: { + topbar: () => import(/* webpackChunkName: "navigation" */ './views/NavDesktop'), + default: () => import(/* webpackChunkName: "about" */ './views/Profile'), + bottombar: () => import(/* webpackChunkName: "navigation" */ './views/NavMobile') + }, beforeEnter: requireAuth }, { path: '/camps', name: 'camps', components: { - default: () => import(/* webpackChunkName: "camps" */ './views/Camps.vue') + topbar: () => import(/* webpackChunkName: "navigation" */ './views/NavDesktop'), + default: () => import(/* webpackChunkName: "camps" */ './views/Camps'), + bottombar: () => import(/* webpackChunkName: "navigation" */ './views/NavMobile') }, beforeEnter: requireAuth }, { path: '/camps/:campId/:campTitle?', components: { - default: () => import(/* webpackChunkName: "camp" */ './views/Camp.vue'), - aside: () => import(/* webpackChunkName: "camps" */ './views/Camps.vue') + topbar: () => import(/* webpackChunkName: "navigation" */ './views/camp/NavDesktop'), + default: () => import(/* webpackChunkName: "camp" */ './views/camp/Camp'), + aside: () => import(/* webpackChunkName: "periods" */ './views/camp/SideBarPeriods'), + bottombar: () => import(/* webpackChunkName: "navigation" */ './views/camp/NavMobile') }, beforeEnter: requireAuth, props: { - default: route => ({ camp: campFromRoute(route) }) + default: route => ({ camp: campFromRoute(route) }), + aside: route => ({ camp: campFromRoute(route) }) }, children: [ { path: 'collaborators', name: 'camp/collaborators', - component: () => import(/* webpackChunkName: "campCollaborators" */ './components/camp/Collaborators.vue'), - meta: { layout: 'camp' } + component: () => import(/* webpackChunkName: "campCollaborators" */ './views/camp/Collaborators') }, { - path: 'periods', - name: 'camp/periods', - component: () => import(/* webpackChunkName: "campPeriods" */ './components/camp/Periods.vue'), - meta: { layout: 'camp' } + path: 'admin', + name: 'camp/admin', + component: () => import(/* webpackChunkName: "campAdmin" */ './views/camp/Admin') }, { - path: 'picasso', - name: 'camp/picasso', - component: () => import(/* webpackChunkName: "campPicasso" */ './components/camp/CampPicasso.vue'), - meta: { layout: 'camp' } + path: 'program', + name: 'camp/program', + component: () => import(/* webpackChunkName: "campProgram" */ './views/camp/CampProgram') }, { path: '', - name: 'camp', - component: () => import(/* webpackChunkName: "campHome" */ './views/camp/CampHome.vue'), - meta: { layout: 'camp' } + redirect: { name: 'camp/program' } } ] }, { - path: '/camps/:campId/:campTitle?/events/:eventInstanceId/:eventName?', + path: '/camps/:campId/:campTitle/events/:eventInstanceId/:eventName?', name: 'event', components: { - default: () => import(/* webpackChunkName: "event" */ './views/Event.vue'), - aside: () => import(/* webpackChunkName: "day" */ './views/DayPicasso.vue') + topbar: () => import(/* webpackChunkName: "navigation" */ './views/camp/NavDesktop'), + default: () => import(/* webpackChunkName: "event" */ './views/event/Event'), + aside: () => import(/* webpackChunkName: "day" */ './views/event/SideBarProgram'), + bottombar: () => import(/* webpackChunkName: "navigation" */ './views/camp/NavMobile') }, beforeEnter: requireAuth, - meta: { layout: 'camp' }, props: { default: route => ({ eventInstance: eventInstanceFromRoute(route) }), aside: route => ({ day: dayFromEventInstanceInRoute(route) }) @@ -130,11 +155,14 @@ function dayFromEventInstanceInRoute (route) { export function campRoute (camp, subroute) { if (camp._meta.loading) return {} - const routeName = subroute ? 'camp/' + subroute : 'camp' + const routeName = subroute ? 'camp/' + subroute : 'camp/program' return { name: routeName, params: { campId: camp.id, campTitle: slugify(camp.title) } } } export function eventInstanceRoute (camp, eventInstance) { if (camp._meta.loading || eventInstance._meta.loading || eventInstance.event()._meta.loading) return {} - return { name: 'event', params: { campId: camp.id, campTitle: slugify(camp.title), eventInstanceId: eventInstance.id, eventName: slugify(eventInstance.event().title) } } + return { + name: 'event', + params: { campId: camp.id, campTitle: slugify(camp.title), eventInstanceId: eventInstance.id, eventName: slugify(eventInstance.event().title) } + } } diff --git a/frontend/src/scss/global.scss b/frontend/src/scss/global.scss new file mode 100644 index 0000000000..b292bc35e1 --- /dev/null +++ b/frontend/src/scss/global.scss @@ -0,0 +1,31 @@ +@use "~inter-ui/default" as inter-ui with ( + $inter-font-path: "~inter-ui/Inter (web hinted latin)" + ); +@include inter-ui.weight-200; +@include inter-ui.weight-400; +@include inter-ui.weight-500; +@include inter-ui.weight-600; +body {font-feature-settings: "ss03", "calt", "rlig", "kern", "cv05", "cv07", "cv08"} +.v-toolbar__title {font-weight: 500;} +.theme--light.v-application { + background: #546E7A!important; +} +.v-calendar-daily, +.v-skeleton-loader__actions, +.v-skeleton-loader__article, +.v-skeleton-loader__card-heading, +.v-skeleton-loader__card-text, +.v-skeleton-loader__date-picker, +.v-skeleton-loader__list-item, +.v-skeleton-loader__list-item-avatar, +.v-skeleton-loader__list-item-text, +.v-skeleton-loader__list-item-two-line, +.v-skeleton-loader__list-item-avatar-two-line, +.v-skeleton-loader__list-item-three-line, +.v-skeleton-loader__list-item-avatar-three-line, +.v-skeleton-loader__table-heading, +.v-skeleton-loader__table-thead, +.v-skeleton-loader__table-tbody, +.v-skeleton-loader__table-tfoot { + background: none!important; +} diff --git a/frontend/src/scss/variables.scss b/frontend/src/scss/variables.scss index 30445b7e35..eb9a6e046b 100644 --- a/frontend/src/scss/variables.scss +++ b/frontend/src/scss/variables.scss @@ -1,13 +1,3 @@ -@use "~inter-ui/default" as inter-ui with ( - $inter-font-path: "~inter-ui/Inter (web)" -); -// TODO: @manuelmeister remove unused charachters (50% savings) -// see https://github.com/filamentgroup/glyphhanger - -// @include inter-ui.weight-200; -// @include inter-ui.weight-400; -// @include inter-ui.weight-600; -@include inter-ui.all; $body-font-family: 'Inter', sans-serif, emoji; $heading-font-family: $body-font-family; $body-font-weight: 400; @@ -54,13 +44,13 @@ $headings: ( ), 'h6': ( 'size': 1.25rem, - 'weight': 500, + 'weight': 600, 'line-height': 1.428571429, 'letter-spacing': -.0125em, 'font-family': $heading-font-family ), 'subtitle-1': ( - 'size': 1rem, + 'size': 1.125rem, 'weight': 400, 'line-height': 1.428571429, 'letter-spacing': -.017em, @@ -102,8 +92,10 @@ $headings: ( 'font-family': $body-font-family ) ); -body {font-feature-settings: "ss03", "calt", "rlig", "kern"} -.v-toolbar__title {font-weight: 500;} $btn-letter-spacing: .25px; +$btn-text-transform: inherit; $bottom-nav-btn-min-width: 60px; $list-item-action-icon-margin: 20px; +$menu-content-border-radius: 0 0 4px 4px; +$primary-transition: .1s ease-in-out !default; + diff --git a/frontend/src/store/storeValueProxy.js b/frontend/src/store/storeValueProxy.js index 01162f9325..a8b06f5b6d 100644 --- a/frontend/src/store/storeValueProxy.js +++ b/frontend/src/store/storeValueProxy.js @@ -90,6 +90,7 @@ function loadingProxy (entityLoaded, uri = null) { } // Normal property access: return a function that yields another loadingProxy and renders as empty string const result = templateParams => loadingProxy(propertyLoaded.then(property => property(templateParams)._meta.load)) + result.loading = true result.toString = () => '' return result } diff --git a/frontend/src/views/Camps.vue b/frontend/src/views/Camps.vue index 21b58b7fc7..86dc3f5904 100644 --- a/frontend/src/views/Camps.vue +++ b/frontend/src/views/Camps.vue @@ -1,41 +1,45 @@ - - - Camps - - - - - - {{ camp.title }} - - {{ camp.name }} - {{ camp.camp_type().organization().name }} - - - - - - mdi-delete - - - - - - + + + + + + + + + + {{ camp.title }} + + {{ camp.name }} - {{ camp.camp_type().organization().name }} + + + + + + mdi-delete + + + + + + + diff --git a/frontend/src/views/Event.vue b/frontend/src/views/Event.vue deleted file mode 100644 index 59ef70b225..0000000000 --- a/frontend/src/views/Event.vue +++ /dev/null @@ -1,82 +0,0 @@ - - - - - - - mdi-arrow-left - - - {{ eventInstance().number }} - {{ category.short }} - {{ event.title }} - - - - - - - - - Instanzen - - - 1. Montag {{ instance.start_time }} bis {{ instance.end_time }} - - - - - - - - - - - diff --git a/frontend/src/views/Home.vue b/frontend/src/views/Home.vue index fbfe424792..1d93cedb91 100644 --- a/frontend/src/views/Home.vue +++ b/frontend/src/views/Home.vue @@ -1,52 +1,52 @@ - - - Home - - - - - mdi-format-list-bulleted-triangle - - - - Camp List - - - - - - mdi-database-plus - - - - Beispiel-Camps laden - - - Dev data - - - - - - mdi-database-plus - - - - Beispiel-Camps laden - - - Prod data - - - - - + + + + + + mdi-format-list-bulleted-triangle + + + Meine Camps + + + + + mdi-database-plus + + + + Beispiel-Camps laden + + + Dev data + + + + + + mdi-database-plus + + + + Beispiel-Camps laden + + + Prod data + + + + + + diff --git a/frontend/src/views/NavDesktop.vue b/frontend/src/views/NavDesktop.vue new file mode 100644 index 0000000000..d90e74c84f --- /dev/null +++ b/frontend/src/views/NavDesktop.vue @@ -0,0 +1,59 @@ + + + + + + + + + + + + diff --git a/frontend/src/views/NavMobile.vue b/frontend/src/views/NavMobile.vue new file mode 100644 index 0000000000..336c7343d1 --- /dev/null +++ b/frontend/src/views/NavMobile.vue @@ -0,0 +1,19 @@ + + + + Meine Camps + mdi-format-list-bulleted-triangle + + + + + + + diff --git a/frontend/src/views/Profile.vue b/frontend/src/views/Profile.vue new file mode 100644 index 0000000000..48a1af8ece --- /dev/null +++ b/frontend/src/views/Profile.vue @@ -0,0 +1,40 @@ + + + + + + + {{ 'Profil: ' + profile.username }} + + + + + + + + + + + + diff --git a/frontend/src/views/auth/Login.vue b/frontend/src/views/auth/Login.vue index 59d62d77b2..cb5cf6c8ef 100644 --- a/frontend/src/views/auth/Login.vue +++ b/frontend/src/views/auth/Login.vue @@ -1,85 +1,76 @@ - - - - 🏕 - eCamp - - - - - - - Login - - Register - - - Login failed - - + + + + + Login + + Register + + + Login failed + + - - - - - - - - - - - Hitobito - - - - - - - - PBS MiData - - - jubla.db - - - - - - Google - - - - Login - - - - - - + + + + + + + + + + + Hitobito + + + + + + + + PBS MiData + + + jubla.db + + + + + + Google + + + + Login + + + + + + + diff --git a/frontend/src/views/auth/Register.vue b/frontend/src/views/auth/Register.vue index 051350de35..062f828bea 100644 --- a/frontend/src/views/auth/Register.vue +++ b/frontend/src/views/auth/Register.vue @@ -1,69 +1,60 @@ - - - - 🏕 - eCamp - - - - - - - Register - - Login - - - - + + + + + Register + + Login + + + + - + - + - - - - - - - Register - - - - - - + + + + + + + Register + + + + + + + diff --git a/frontend/src/views/Camp.vue b/frontend/src/views/camp/Camp.vue similarity index 75% rename from frontend/src/views/Camp.vue rename to frontend/src/views/camp/Camp.vue index daf7445863..41cf9d9c0e 100644 --- a/frontend/src/views/Camp.vue +++ b/frontend/src/views/camp/Camp.vue @@ -3,7 +3,9 @@ Displays several tabs with details on a single camp. --> - + + + - - diff --git a/frontend/src/views/camp/CampProgram.vue b/frontend/src/views/camp/CampProgram.vue new file mode 100644 index 0000000000..212bace60e --- /dev/null +++ b/frontend/src/views/camp/CampProgram.vue @@ -0,0 +1,114 @@ + + + + + + + + mdi-calendar-month + mdi-menu + + + + + + + + + + + mdi-plus + + + + + + + + + diff --git a/frontend/src/views/camp/Collaborators.vue b/frontend/src/views/camp/Collaborators.vue new file mode 100644 index 0000000000..6efb23e76a --- /dev/null +++ b/frontend/src/views/camp/Collaborators.vue @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{ result.username }} + {{ result.mail }} + + + + Member + + + + + Manager + + + + + + + + + + + diff --git a/frontend/src/views/camp/NavDesktop.vue b/frontend/src/views/camp/NavDesktop.vue new file mode 100644 index 0000000000..3ff5cc7651 --- /dev/null +++ b/frontend/src/views/camp/NavDesktop.vue @@ -0,0 +1,56 @@ + + + + + + {{ camp().title | loading('Camp wird geladen…') }} + + + + + + + mdi-account-group + Team + + + mdi-cogs + Admin + + + + + + + + + + + diff --git a/frontend/src/views/camp/NavMobile.vue b/frontend/src/views/camp/NavMobile.vue new file mode 100644 index 0000000000..02c80405ad --- /dev/null +++ b/frontend/src/views/camp/NavMobile.vue @@ -0,0 +1,35 @@ + + + + Material + mdi-package-variant + + + Tasks + mdi-format-list-checks + + + Camp + mdi-tent + + + Team + mdi-account-group + + + Admin + mdi-cogs + + + + + + + diff --git a/frontend/src/views/camp/SideBarPeriods.vue b/frontend/src/views/camp/SideBarPeriods.vue new file mode 100644 index 0000000000..a17c625447 --- /dev/null +++ b/frontend/src/views/camp/SideBarPeriods.vue @@ -0,0 +1,50 @@ + + + + + + + Periods + + + + + {{ period.description }} + {{ period.start }} - {{ period.end }} + + + + + + + diff --git a/frontend/src/views/event/Event.vue b/frontend/src/views/event/Event.vue new file mode 100644 index 0000000000..b2eae5be6f --- /dev/null +++ b/frontend/src/views/event/Event.vue @@ -0,0 +1,86 @@ + + + + + + + + + {{ eventInstance().number }} + {{ category.short }} + {{ event.title }} + + + + + + + + + Instanzen + + + 1. Montag {{ instance.start_time }} bis {{ instance.end_time }} + + + + + + + + + + + + diff --git a/frontend/src/views/event/SideBarProgram.vue b/frontend/src/views/event/SideBarProgram.vue new file mode 100644 index 0000000000..5d8489344e --- /dev/null +++ b/frontend/src/views/event/SideBarProgram.vue @@ -0,0 +1,55 @@ + + + + + Tagesübersicht + + + + + + + + diff --git a/frontend/tests/e2e/specs/test.js b/frontend/tests/e2e/specs/test.js index 8b54c1358f..8cb264699f 100644 --- a/frontend/tests/e2e/specs/test.js +++ b/frontend/tests/e2e/specs/test.js @@ -3,6 +3,5 @@ describe('My First Test', () => { it('Visits the app root url', () => { cy.visit('/') - cy.contains('.v-toolbar__title', 'eCamp') }) }) diff --git a/frontend/tests/unit/api-store.spec.js b/frontend/tests/unit/api-store.spec.js index 78ea5706bf..0fe0bcceeb 100644 --- a/frontend/tests/unit/api-store.spec.js +++ b/frontend/tests/unit/api-store.spec.js @@ -700,7 +700,7 @@ describe('API store', () => { axiosMock.onGet('http://localhost/periods/1').networkError() axiosMock.onGet('http://localhost/days/2').reply(404) const load = vm.api.get('/camps/3')._meta.load - vm.api.get('/periods/1')._meta.load + const period = vm.api.get('/periods/1')._meta.load await letNetworkRequestFinish() const camp = await load expect(vm.$store.state.api).toMatchObject(circularReference.storeState) @@ -711,6 +711,7 @@ describe('API store', () => { // then await letNetworkRequestFinish() expect(axiosMock.history.get.length).toBe(3) + await period done() }) @@ -893,4 +894,12 @@ describe('API store', () => { expect(await load).toMatchObject({ id: 83, name: 'Pflock', _meta: { self: 'http://localhost/camps/1/users/83' } }) done() }) + + it('sets property loading on LoadingProxy to true', async done => { + // given + axiosMock.onGet('http://localhost/camps/1').reply(200, embeddedSingleEntity.serverResponse) + const loadingProxy = vm.api.get('/camps/1') + expect(loadingProxy.loading).toBe(true) + done() + }) })