UI: Refactor for user course list

pull/4344/head
Angel Fernando Quiroz Campos 2 years ago
parent acb6d36638
commit 0ace78c403
  1. 7
      assets/css/scss/atoms/_skeleton.scss
  2. 8
      assets/css/scss/index.scss
  3. 21
      assets/css/scss/molecules/_empty_state.scss
  4. 42
      assets/vue/components/EmptyState.vue
  5. 39
      assets/vue/layouts/MyCourses.vue
  6. 4
      assets/vue/router/index.js
  7. 104
      assets/vue/views/user/courses/List.vue

@ -0,0 +1,7 @@
.p-skeleton {
@apply bg-gray-30 rounded-lg w-full;
&:after {
@apply bg-gradient-to-r from-transparent via-gray-15 to-transparent;
}
}

@ -5,6 +5,12 @@
//@import 'inbox';
//@import 'install';
@layer base {
hr {
@apply text-gray-30 my-6;
}
}
@import "settings/typography";
@import "atoms/buttons";
@ -14,9 +20,11 @@
@import "atoms/input_text";
@import "atoms/messages";
@import "atoms/overlay";
@import "atoms/skeleton";
@import "molecules/course_tool";
@import "molecules/datepicker";
@import "molecules/empty_state";
@import "organisms/modals";
@import "organisms/sidebar";

@ -0,0 +1,21 @@
@layer components {
.empty-state {
@apply border border-solid border-support-1 bg-gray-10 flex flex-auto justify-center items-center p-10 rounded-lg;
&__container {
@apply flex flex-col items-center text-center w-60;
}
&__icon {
@apply mb-4 text-9xl text-transparent bg-clip-text bg-gradient-to-br from-primary to-primary-gradient w-32 h-32;
}
&__summary {
@apply text-body-2-bold text-gray-90;
}
&__detail {
@apply text-body-2 text-gray-90;
}
}
}

@ -0,0 +1,42 @@
<template>
<div
class="empty-state"
>
<div class="empty-state__container">
<span
aria-hidden="true"
class="empty-state__icon"
:class="icon"
/>
<p
class="empty-state__summary"
v-text="summary"
/>
<p
class="empty-state__detail"
v-text="detail"
/>
</div>
</div>
</template>
<script setup>
// eslint-disable-next-line no-undef
defineProps({
summary: {
type: String,
default: '',
required: true,
},
detail: {
type: String,
default: '',
required: false,
},
icon: {
type: String,
default: '',
required: false,
},
});
</script>

@ -1,13 +1,30 @@
<template>
<q-layout>
<!-- <q-tabs align="left" dense inline-label no-caps>-->
<!-- <q-route-tab to="/courses" label="My courses" />-->
<!-- <q-route-tab to="/sessions" label="My sessions" />-->
<!-- </q-tabs>-->
<!-- this is where the Pages are injected -->
<q-page-container>
<router-view></router-view>
</q-page-container>
</q-layout>
<div class="flex justify-between items-center">
<h2 v-t="'My Courses'" />
<Button
v-if="isTeacher"
class="p-button-secondary md:hidden"
icon="pi pi-plus"
/>
<Button
v-if="isTeacher"
:label="t('Course')"
class="p-button-secondary hidden md:inline-flex"
icon="pi pi-plus"
/>
</div>
<hr>
<router-view />
</template>
<script setup>
import Button from 'primevue/button';
import { computed } from 'vue';
import { useStore } from 'vuex';
import { useI18n } from 'vue-i18n';
const store = useStore();
const { t } = useI18n();
const isTeacher = computed(() => store.getters['security/hasRole']('ROLE_TEACHER'));
</script>

@ -67,7 +67,9 @@ const router = createRouter({
component: MyCoursesLayout,
children: [
{
path: '/courses', name: 'MyCourses', component: MyCourseList,
path: '',
name: 'MyCourses',
component: MyCourseList,
meta: {requiresAuth: true},
},
]

@ -1,71 +1,75 @@
<template>
<StickyCourses />
<!-- {{ loading }}-->
<div
v-if="courses.length"
class="grid gap-4 grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 mt-2">
<CourseCardList
:courses="courses"
v-if="isLoading"
class="grid gap-4 grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4"
>
<Skeleton
height="16rem"
/>
</div>
<div v-else>
<div class="bg-gradient-to-r from-gray-100 to-gray-50 flex flex-col rounded-md text-center p-2">
<div class="p-10 text-center">
<div>
<v-icon
icon="mdi-book-open-page-variant"
size="72px"
class="font-extrabold text-transparent bg-clip-text bg-gradient-to-br from-primary to-primary-gradient"
<Skeleton
class="hidden md:block"
height="16rem"
/>
<Skeleton
class="hidden lg:block"
height="16rem"
/>
<Skeleton
class="hidden xl:block"
height="16rem"
/>
</div>
<div class="mt-2 font-bold">
{{ $t("You don't have any course yet.") }}
</div>
<div>
{{ $t('Go to "Explore" to find a topic of interest, or wait for someone to subscribe you.') }}
</div>
</div>
</div>
<div
v-if="!isLoading && courses.length > 0"
class="grid gap-4 grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4"
>
<CourseCardList
:courses="courses"
/>
</div>
<EmptyState
v-else-if="!isLoading && 0 === courses.length"
:detail="t('Go to Explore to find a topic of interest, or wait for someone to subscribe you')"
:summary="t('You don\'t have any course yet')"
icon="mdi mdi-book-open-page-variant"
/>
</template>
<script>
import CourseCardList from '../../../components/course/CourseCardList.vue';
import {computed} from "vue";
<script setup>
import { computed, ref } from 'vue';
import { useStore } from 'vuex';
import {useQuery, useResult} from '@vue/apollo-composable'
import {GET_COURSE_REL_USER} from "../../../graphql/queries/CourseRelUser.js";
import { useQuery } from '@vue/apollo-composable';
import { useI18n } from 'vue-i18n';
import { GET_COURSE_REL_USER } from '../../../graphql/queries/CourseRelUser.js';
import Skeleton from 'primevue/skeleton';
import StickyCourses from '../../../views/user/courses/StickyCourses.vue';
import CourseCardList from '../../../components/course/CourseCardList.vue';
import EmptyState from '../../../components/EmptyState';
export default {
name: 'CourseList',
components: {
StickyCourses,
CourseCardList,
},
setup() {
const store = useStore();
const { t } = useI18n();
let user = computed(() => store.getters['security/getUser']);
let courses = ref([]);
let isLoading = ref(true);
if (user.value) {
let userId = user.value.id;
const {result, loading, error} = useQuery(GET_COURSE_REL_USER, {
user: "/api/users/" + userId
});
const { result, loading } = useQuery(
GET_COURSE_REL_USER,
{
user: user.value['@id'],
}
);
const courses = useResult(result, [], (data) => {
return data.courseRelUsers.edges.map(function (edge) {
return edge.node.course;
});
});
isLoading = computed(
() => loading.value
);
return {
courses,
loading
}
}
courses = computed(
() => result.value?.courseRelUsers.edges.map(({ node }) => node.course) ?? []
);
}
};
</script>

Loading…
Cancel
Save