tum 2 years ago
parent
commit
c1945c986f

+ 9 - 0
package-lock.json

@@ -23,6 +23,7 @@
23 23
         "@vimeo/player": "^2.20.1",
24 24
         "axios": "^1.6.0",
25 25
         "ionicons": "^7.0.0",
26
+        "moment": "^2.29.4",
26 27
         "vue": "^3.2.45",
27 28
         "vue-core-video-player": "^0.2.0",
28 29
         "vue-router": "^4.1.6",
@@ -7399,6 +7400,14 @@
7399 7400
         "ufo": "^1.3.0"
7400 7401
       }
7401 7402
     },
7403
+    "node_modules/moment": {
7404
+      "version": "2.29.4",
7405
+      "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
7406
+      "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==",
7407
+      "engines": {
7408
+        "node": "*"
7409
+      }
7410
+    },
7402 7411
     "node_modules/ms": {
7403 7412
       "version": "2.1.2",
7404 7413
       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",

+ 1 - 0
package.json

@@ -27,6 +27,7 @@
27 27
     "@vimeo/player": "^2.20.1",
28 28
     "axios": "^1.6.0",
29 29
     "ionicons": "^7.0.0",
30
+    "moment": "^2.29.4",
30 31
     "vue": "^3.2.45",
31 32
     "vue-core-video-player": "^0.2.0",
32 33
     "vue-router": "^4.1.6",

+ 37 - 0
src/components/Course.vue

@@ -0,0 +1,37 @@
1
+<template>
2
+  <ion-card :router-link="'/tabs/course_detail/'+courseObj.id">
3
+    <img alt="Silhouette of mountains" :src="courseObj.feature_img"  v-if="courseObj.feature_img" />
4
+    <ion-card-header>
5
+      <ion-card-title>{{ courseObj.name }}</ion-card-title>
6
+      <ion-card-subtitle>{{ courseObj.description }}</ion-card-subtitle>
7
+    </ion-card-header>
8
+
9
+    <ion-card-content class='ion-text-wrap'>
10
+      {{ courseObj.description }}
11
+    </ion-card-content>
12
+  </ion-card>
13
+</template>
14
+
15
+<script setup lang="ts">
16
+  import { IonPage, IonHeader, IonToolbar, IonTitle, IonContent, IonIcon, onIonViewWillEnter, IonCard, IonCardHeader, IonCardTitle, IonCardSubtitle, IonCardContent } from '@ionic/vue';
17
+
18
+import { getTrainers, listCourses } from '@/settings';
19
+  import { ref, onMounted } from 'vue'
20
+  const props = defineProps({
21
+    courseObj: Object,
22
+  })
23
+
24
+  onMounted(() => {
25
+    console.log("--- onmounted ---")
26
+    console.log("name === ", props.courseObj)
27
+  })
28
+</script>
29
+
30
+<style scoped>
31
+#container {
32
+  background-color:#f00;
33
+}
34
+ion-card-title {
35
+  font-size:1.5em;
36
+}
37
+</style>

+ 53 - 0
src/components/CourseMat.vue

@@ -0,0 +1,53 @@
1
+<template>
2
+  <ion-card :router-link="'/tabs/mat_detail/'+obj.id">
3
+    <img alt="Silhouette of mountains" :src="thmb"  v-if="thmb" />
4
+    <ion-card-header>
5
+      <ion-card-title>{{ name }}</ion-card-title>
6
+    </ion-card-header>
7
+
8
+    <ion-card-content class='ion-text-wrap'>
9
+      {{ dt }}
10
+    </ion-card-content>
11
+  </ion-card>
12
+</template>
13
+
14
+<script setup lang="ts">
15
+  import { IonPage, IonHeader, IonToolbar, IonTitle, IonContent, IonIcon, onIonViewWillEnter, IonCard, IonCardHeader, IonCardTitle, IonCardSubtitle, IonCardContent } from '@ionic/vue';
16
+  import moment from 'moment'
17
+import { getTrainers, listCourses } from '@/settings';
18
+  import { ref, onMounted  } from 'vue'
19
+
20
+  const props = defineProps({
21
+    obj: Object,
22
+    courseName: String,
23
+  })
24
+
25
+  const dt = ref()
26
+  const thmb = ref()
27
+  const name = ref()
28
+
29
+  onMounted(() => {
30
+    console.log("--- onmounted ---")
31
+    console.log("name === ", props.obj)
32
+    const obj = props.obj
33
+    let temp  = obj.display_datetime || obj.vimeo_created || obj.created_at 
34
+    dt.value = moment(temp).format('LLL'); 
35
+
36
+    if( obj.gifs && obj.gifs.length > 0 ) {
37
+      thmb.value = obj.gifs[0].sizes[2].link
38
+    }else {
39
+      thmb.value = obj.course_image
40
+    }
41
+    name.value = obj.vimeo_name || props.courseName
42
+  })
43
+  
44
+</script>
45
+
46
+<style scoped>
47
+#container {
48
+  background-color:#f00;
49
+}
50
+ion-card-title {
51
+  font-size:1.5em;
52
+}
53
+</style>

+ 10 - 0
src/router/index.ts

@@ -35,6 +35,16 @@ const routes: Array<RouteRecordRaw> = [
35 35
         path: 'detail/:id/',
36 36
         name: 'Detail', 
37 37
         component: () => import('@/views/DetailPage.vue')
38
+      },
39
+      {
40
+        path: 'course_detail/:id/',
41
+        name: 'course_detail', 
42
+        component: () => import('@/views/CourseDetailPage.vue')
43
+      },
44
+      {
45
+        path: 'mat_detail/:id/',
46
+        name: 'mat_detail', 
47
+        component: () => import('@/views/CourseMatDetailPage.vue')
38 48
       }
39 49
     ]
40 50
   }

+ 49 - 0
src/settings.ts

@@ -63,6 +63,42 @@ export const listMats = async  () => {
63 63
   console.log(data)
64 64
   return data.results
65 65
 }
66
+export const listCourses = async  () => {
67
+
68
+  const token = await Preferences.get({ key: 'token' });
69
+  console.log("token = ", token)
70
+  const { data } = await axios.get(BASE_URL + "backend/api/courses/?limit=1000&ordering=-id&status=active", {
71
+    headers: { 
72
+    'Authorization': `Token ${token.value}`
73
+    }
74
+  })
75
+  console.log(data)
76
+  return data.results
77
+}
78
+export const getCourse = async  (pk) => {
79
+
80
+  const token = await Preferences.get({ key: 'token' });
81
+  console.log("token = ", token)
82
+  const { data } = await axios.get(BASE_URL + "backend/api/courses/"+pk+"/", {
83
+    headers: { 
84
+    'Authorization': `Token ${token.value}`
85
+    }
86
+  })
87
+  console.log(data)
88
+  return data
89
+}
90
+export const getMat = async(pk) => {
91
+
92
+  const token = await Preferences.get({ key: 'token' });
93
+  console.log("token = ", token)
94
+  const { data } = await axios.get(BASE_URL + `backend/api/mats/${pk}/`, {
95
+    headers: { 
96
+    'Authorization': `Token ${token.value}`
97
+    }
98
+  })
99
+  console.log(data)
100
+  return data
101
+}
66 102
 
67 103
 export const storeAPNToken = async (device_token) => {
68 104
   
@@ -77,3 +113,16 @@ export const storeAPNToken = async (device_token) => {
77 113
   console.log(data)
78 114
   return data
79 115
 }
116
+
117
+
118
+export const listCourseMats = async  (cid) => {
119
+  const token = await Preferences.get({ key: 'token' });
120
+  console.log("token = ", token)
121
+  const { data } = await axios.get(BASE_URL + "backend/api/courses/"+cid+"/mats/?limit=100", {
122
+    headers: { 
123
+    'Authorization': `Token ${token.value}`
124
+    }
125
+  })
126
+  console.log(data)
127
+  return data
128
+}

+ 48 - 0
src/views/CourseDetailPage.vue

@@ -0,0 +1,48 @@
1
+
2
+<template>
3
+  <ion-page>
4
+    <ion-header>
5
+      <ion-toolbar>
6
+        <ion-buttons slot="start">
7
+          <ion-back-button></ion-back-button>
8
+          </ion-buttons>
9
+          <ion-title v-if="course">{{ course.name }}</ion-title>
10
+      </ion-toolbar>
11
+    </ion-header>
12
+    <ion-content :fullscreen="true">
13
+      <ion-header collapse="condense">
14
+        <ion-toolbar>
15
+          <ion-title size="large" v-if="course">{{ course.name }}</ion-title>
16
+        </ion-toolbar>
17
+      </ion-header>
18
+      <ion-grid>
19
+        <ion-row>
20
+          <ion-col size="12" size-md="4" size-lg="2" v-for="c in mats">
21
+            <CourseMat :obj="c" :course-name="course.name" />
22
+          </ion-col>
23
+        </ion-row>
24
+      </ion-grid> 
25
+    </ion-content>
26
+  </ion-page>
27
+</template>
28
+
29
+<script setup lang="ts">
30
+import { IonPage, IonHeader, IonToolbar, IonTitle, IonContent,   IonNavLink,
31
+    IonButton,
32
+    IonButtons,
33
+    IonBackButton, onIonViewWillEnter, IonRow, IonGrid, IonCol } from '@ionic/vue';
34
+import { useRoute } from 'vue-router';
35
+import { listCourseMats, getCourse } from '@/settings';
36
+import { ref } from 'vue';
37
+import CourseMat from '@/components/CourseMat.vue'
38
+
39
+const route = useRoute();
40
+const { id } = route.params;
41
+
42
+const mats = ref([])
43
+const course = ref()
44
+onIonViewWillEnter(async () => {
45
+  course.value = await getCourse(id)
46
+  mats.value = await listCourseMats(id)
47
+})
48
+</script>

+ 41 - 0
src/views/CourseMatDetailPage.vue

@@ -0,0 +1,41 @@
1
+
2
+<template>
3
+  <ion-page>
4
+    <ion-header>
5
+      <ion-toolbar>
6
+          <ion-buttons slot="start">
7
+            <ion-back-button></ion-back-button>
8
+          </ion-buttons>
9
+          <ion-title>Material Detail</ion-title>
10
+      </ion-toolbar>
11
+    </ion-header>
12
+    <ion-content class='ion-text-wrap'>
13
+      <div style="padding:56.25% 0 0 0;position:relative;" v-html="mat.embed" v-if='mat'></div>
14
+      <div v-if="mat" class='ion-padding ion-text-wrap'>
15
+        <h2 v-if='name'>{{ name }}</h2>
16
+        {{ mat }}
17
+      </div> 
18
+    </ion-content>
19
+  </ion-page>
20
+</template>
21
+
22
+<script setup lang="ts">
23
+import { IonPage, IonHeader, IonToolbar, IonTitle, IonContent,   IonNavLink,
24
+    IonButton,
25
+    IonButtons,
26
+    IonBackButton, onIonViewWillEnter, IonRow, IonGrid, IonCol } from '@ionic/vue';
27
+import { useRoute } from 'vue-router';
28
+import { getMat } from '@/settings';
29
+import { ref } from 'vue';
30
+import CourseMat from '@/components/CourseMat.vue'
31
+
32
+const route = useRoute();
33
+const { id } = route.params;
34
+
35
+const mat = ref()
36
+const name = ref()
37
+onIonViewWillEnter(async () => {
38
+  mat.value = await getMat(id)
39
+  name.value = mat.value.vimeo_name || mat.value.course_name
40
+})
41
+</script>

+ 20 - 6
src/views/Tab2Page.vue

@@ -2,22 +2,36 @@
2 2
   <ion-page>
3 3
     <ion-header>
4 4
       <ion-toolbar>
5
-        <ion-title>Tab 2</ion-title>
5
+        <ion-title>Courses</ion-title>
6 6
       </ion-toolbar>
7 7
     </ion-header>
8 8
     <ion-content :fullscreen="true">
9 9
       <ion-header collapse="condense">
10 10
         <ion-toolbar>
11
-          <ion-title size="large">Tab 2</ion-title>
11
+          <ion-title size="large">Courses</ion-title>
12 12
         </ion-toolbar>
13 13
       </ion-header>
14
-
15
-      <ExploreContainer name="Tab 2 page" />
14
+      <ion-grid>
15
+        <ion-row>
16
+          <ion-col size="12" size-md="4" size-lg="2" v-for="c in courses">
17
+            <Course :course-obj="c" />
18
+          </ion-col>
19
+        </ion-row>
20
+      </ion-grid>
16 21
     </ion-content>
17 22
   </ion-page>
18 23
 </template>
19 24
 
20 25
 <script setup lang="ts">
21
-import { IonPage, IonHeader, IonToolbar, IonTitle, IonContent } from '@ionic/vue';
22
-import ExploreContainer from '@/components/ExploreContainer.vue';
26
+import { IonPage, IonHeader, IonToolbar, IonTitle, IonContent, IonGrid, IonRow, IonCol, onIonViewWillEnter } from '@ionic/vue';
27
+import Course from '@/components/Course.vue';
28
+import { ref } from 'vue';
29
+
30
+import {listCourses} from '@/settings';
31
+const courses = ref([])
32
+
33
+onIonViewWillEnter(async () => {
34
+
35
+  courses.value = await listCourses()
36
+})
23 37
 </script>