Просмотр исходного кода

Merge branch 'spider-graph' of fyindr/siimee into dev

tags/0.0.2
maeda 3 лет назад
Родитель
Сommit
6bc1fa76c2

+ 11
- 0
frontend/package-lock.json Просмотреть файл

@@ -8,6 +8,7 @@
8 8
             "name": "vite-project",
9 9
             "version": "0.0.0",
10 10
             "dependencies": {
11
+                "chart.js": "^3.9.1",
11 12
                 "joi": "^17.6.0",
12 13
                 "pubnub": "^5.0.0",
13 14
                 "vue": "^3.2.31",
@@ -1288,6 +1289,11 @@
1288 1289
                 "is-regex": "^1.0.3"
1289 1290
             }
1290 1291
         },
1292
+        "node_modules/chart.js": {
1293
+            "version": "3.9.1",
1294
+            "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.9.1.tgz",
1295
+            "integrity": "sha512-Ro2JbLmvg83gXF5F4sniaQ+lTbSv18E+TIf2cOeiH1Iqd2PGFOtem+DUufMZsCJwFE7ywPOpfXFBwRTGq7dh6w=="
1296
+        },
1291 1297
         "node_modules/chokidar": {
1292 1298
             "version": "3.5.3",
1293 1299
             "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
@@ -6918,6 +6924,11 @@
6918 6924
                 "is-regex": "^1.0.3"
6919 6925
             }
6920 6926
         },
6927
+        "chart.js": {
6928
+            "version": "3.9.1",
6929
+            "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.9.1.tgz",
6930
+            "integrity": "sha512-Ro2JbLmvg83gXF5F4sniaQ+lTbSv18E+TIf2cOeiH1Iqd2PGFOtem+DUufMZsCJwFE7ywPOpfXFBwRTGq7dh6w=="
6931
+        },
6921 6932
         "chokidar": {
6922 6933
             "version": "3.5.3",
6923 6934
             "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",

+ 1
- 0
frontend/package.json Просмотреть файл

@@ -12,6 +12,7 @@
12 12
         "test": "ava"
13 13
     },
14 14
     "dependencies": {
15
+        "chart.js": "^3.9.1",
15 16
         "joi": "^17.6.0",
16 17
         "pubnub": "^5.0.0",
17 18
         "vue": "^3.2.31",

+ 27
- 10
frontend/src/components/ProfileCard.vue Просмотреть файл

@@ -1,5 +1,5 @@
1 1
 <template lang="pug">
2
-w-card.profile-card-list--card.xs12.pa12
2
+w-card.profile-card-list--card.xs12
3 3
     header.xs12.w-flex.column.center
4 4
         NamePlate(
5 5
             :is-list='isList'
@@ -10,12 +10,17 @@ w-card.profile-card-list--card.xs12.pa12
10 10
             :role='card.role'
11 11
         )
12 12
 
13
-        w-button.text-upper.xs12.pa6(v-if='isPaired && !isList')
14
-            w-icon.mr1(xl) mdi mdi-chat
15
-            | start chat
16
-
17 13
         template(v-if='!isList')
18
-            SummaryBar(:is-tab='isPaired' :tab-content='card.summary')
14
+            w-button.text-upper.xs12.pa6(v-if='currentTab == 0 && isPaired')
15
+                w-icon.mr1(xl) mdi mdi-chat
16
+                | start chat
17
+
18
+            SummaryBar(
19
+                :aspects='aspects'
20
+                :is-tab='isPaired'
21
+                :tab-content='card.summary'
22
+                @tab-change='onTab'
23
+            )
19 24
             TagList(v-if='!isPaired || isList')
20 25
 
21 26
     article.xs12.w-flex.column.justify-space-between
@@ -27,10 +32,13 @@ w-card.profile-card-list--card.xs12.pa12
27 32
             v-if='!isPaired || isList'
28 33
         )
29 34
 
30
-    footer(v-if='!isList && !isPaired')
31
-        .pa12
35
+    footer
36
+        .pa12(v-if='!isPaired && !isList')
32 37
             p {{ card.summary.about.tab }}
33 38
         PairingButton(@pair='onPair' @pass='onPass' v-if='!isPaired')
39
+        w-button.text-upper.xs12.pa6(v-else-if='currentTab != 0')
40
+            w-icon.mr1(xl) mdi mdi-chat
41
+            | start chat
34 42
 </template>
35 43
 
36 44
 <script setup>
@@ -49,8 +57,8 @@ import TagList from './TagList.vue'
49 57
 import PairingButton from './PairingButton.vue'
50 58
 
51 59
 const router = useRouter()
52
-// const isPaired = ref(true)
53
-const isPaired = ref(false)
60
+const isPaired = ref(true)
61
+// const isPaired = ref(false)
54 62
 
55 63
 const props = defineProps({
56 64
     card: {
@@ -68,6 +76,15 @@ const props = defineProps({
68 76
     },
69 77
 })
70 78
 
79
+/**
80
+ * Track tab state for conditional rendering
81
+ */
82
+const currentTab = ref(0)
83
+const onTab = tabIndex => {
84
+    if (currentTab.value == tabIndex) return
85
+    currentTab.value = tabIndex
86
+}
87
+
71 88
 /**
72 89
  * Attempt to pair with target profile
73 90
  * Creates a grouping, and a membership

+ 109
- 0
frontend/src/components/ProfileCardItem.vue Просмотреть файл

@@ -0,0 +1,109 @@
1
+<template lang="pug">
2
+w-card.profile-card-list--card.xs12.pa12
3
+    header.xs12.w-flex.column.center
4
+        NamePlate(
5
+            :is-list='isList'
6
+            :is-paired='isPaired'
7
+            :name='card.name'
8
+            :pid='card.pid'
9
+            :pronouns='card.pronouns'
10
+            :role='card.role'
11
+        )
12
+
13
+        w-button.text-upper.xs12.pa6(v-if='isPaired && !isList')
14
+            w-icon.mr1(xl) mdi mdi-chat
15
+            | start chat
16
+
17
+        template(v-if='!isList')
18
+            SummaryBar(:is-tab='isPaired' :tab-content='card.summary')
19
+            TagList(v-if='!isPaired || isList')
20
+
21
+    article.xs12.w-flex.column.justify-space-between
22
+        AspectBar(
23
+            :key='aspect.name'
24
+            :labels='aspect.labels'
25
+            :percentage='aspect.percentage'
26
+            v-for='aspect in aspects'
27
+            v-if='!isPaired || isList'
28
+        )
29
+
30
+    footer(v-if='!isList && !isPaired')
31
+        .pa12
32
+            p {{ card.summary.about.tab }}
33
+        PairingButton(@pair='onPair' @pass='onPass' v-if='!isPaired')
34
+</template>
35
+
36
+<script setup>
37
+import { ref } from 'vue'
38
+import { useRouter } from 'vue-router'
39
+import {
40
+    updateQueueByProfileId,
41
+    postMembershipByProfileId,
42
+    currentProfile,
43
+} from '../services'
44
+
45
+import NamePlate from './NamePlate.vue'
46
+import AspectBar from './AspectBar.vue'
47
+import SummaryBar from './SummaryBar.vue'
48
+import TagList from './TagList.vue'
49
+import PairingButton from './PairingButton.vue'
50
+
51
+const router = useRouter()
52
+// const isPaired = ref(true)
53
+const isPaired = ref(false)
54
+
55
+const props = defineProps({
56
+    card: {
57
+        type: Object,
58
+        required: true,
59
+    },
60
+    aspects: {
61
+        type: Array,
62
+        required: true,
63
+    },
64
+    isList: {
65
+        type: Boolean,
66
+        required: false,
67
+        default: true,
68
+    },
69
+})
70
+
71
+/**
72
+ * Attempt to pair with target profile
73
+ * Creates a grouping, and a membership
74
+ * for both profileId and targetId
75
+ */
76
+const onPair = async () => {
77
+    const group = await postMembershipByProfileId({
78
+        profileId: currentProfile.id.value,
79
+        targetId: props.card.pid,
80
+    })
81
+    updateQueueByProfileId(currentProfile.id.value, props.card.pid, false)
82
+    currentProfile.getGroupings()
83
+    console.warn('created grouping:', group)
84
+
85
+    let goToRoute = { name: 'HomeView' }
86
+    // if (group.membershipMatch.hasMatch) {
87
+    //     goToRoute = { name: 'PairsView' }
88
+    // }
89
+    router.push(goToRoute)
90
+}
91
+
92
+/**
93
+ * Send to the back of the matchQueue
94
+ * and forward back home
95
+ */
96
+const onPass = async () => {
97
+    updateQueueByProfileId(currentProfile.id.value, props.card.pid, true)
98
+    router.push({ name: 'HomeView' })
99
+}
100
+</script>
101
+
102
+<style lang="sass">
103
+.profile-card-list--card
104
+    background-color: #000
105
+    color: #fff
106
+    header > .w-button
107
+        background-color: #116006
108
+        color: #fff
109
+</style>

+ 2
- 2
frontend/src/components/ProfileCardList.vue Просмотреть файл

@@ -4,7 +4,7 @@ section.profile-card-list.xs12.w-flex.column
4 4
         w-select(:items="['one', 'two', 'three']" outline) Label
5 5
     
6 6
     article
7
-        ProfileCard.match-layout(
7
+        ProfileCardItem.match-layout(
8 8
             v-for="(card, i) in cards"
9 9
             :key="`${card.pid}-${i}`"
10 10
             :card="card"
@@ -21,7 +21,7 @@ import {
21 21
     postMembershipByProfileId,
22 22
     currentProfile,
23 23
 } from '../services'
24
-import ProfileCard from './ProfileCard.vue'
24
+import ProfileCardItem from './ProfileCardItem.vue'
25 25
 
26 26
 class Aspect {
27 27
     constructor({ name, labels, percentage = 50 }) {

+ 91
- 0
frontend/src/components/SpiderChart.vue Просмотреть файл

@@ -0,0 +1,91 @@
1
+<template lang="pug">
2
+.spider-chart.w-flex.pt6.pb6
3
+    canvas#spider-chart-canvas
4
+</template>
5
+
6
+<script setup>
7
+import { Chart, registerables } from 'chart.js'
8
+import { onMounted } from 'vue'
9
+
10
+const props = defineProps({
11
+    profileName: {
12
+        required: true,
13
+        type: String,
14
+    },
15
+    profileData: {
16
+        required: true,
17
+        type: Object,
18
+    },
19
+    targetData: {
20
+        required: true,
21
+        type: Object,
22
+    },
23
+    labels: {
24
+        required: true,
25
+        type: Array,
26
+    },
27
+})
28
+
29
+const chartStyleDefaults = {
30
+    borderWidth: '1px',
31
+    fill: true,
32
+}
33
+const profile = {
34
+    label: props.profileName,
35
+    data: props.profileData,
36
+    backgroundColor: 'rgba(242, 205, 92, 0.3)',
37
+    borderColor: '#F2CD5C',
38
+    ...chartStyleDefaults,
39
+}
40
+const role = {
41
+    label: 'Role',
42
+    data: props.targetData,
43
+    backgroundColor: 'rgba(3, 136, 166, 0.30)',
44
+    borderColor: '#0388A6',
45
+    ...chartStyleDefaults,
46
+}
47
+
48
+const options = {
49
+    plugins: {
50
+        legend: {
51
+            position: 'bottom',
52
+            labels: {
53
+                color: '#FFFFFF',
54
+                boxWidth: 10,
55
+            },
56
+        },
57
+    },
58
+    scales: {
59
+        r: {
60
+            angleLines: {
61
+                color: '#FFFFFF',
62
+            },
63
+            grid: {
64
+                color: '#EAF0F4',
65
+                lineWidth: 1,
66
+            },
67
+            pointLabels: {
68
+                color: '#FFFFFF',
69
+            },
70
+            suggestedMax: 6,
71
+            ticks: {
72
+                display: false,
73
+                stepSize: 1.6,
74
+            },
75
+        },
76
+    },
77
+}
78
+
79
+onMounted(() => {
80
+    Chart.register(...registerables)
81
+    const ctx = document.getElementById('spider-chart-canvas')
82
+    new Chart(ctx, {
83
+        type: 'radar',
84
+        data: {
85
+            labels: props.labels,
86
+            datasets: [profile, role],
87
+        },
88
+        options,
89
+    })
90
+})
91
+</script>

+ 44
- 12
frontend/src/components/SummaryBar.vue Просмотреть файл

@@ -1,51 +1,73 @@
1 1
 <template lang="pug">
2 2
 section.w-flex.column.pb5
3 3
     nav.fill-width.w-flex.column.justify-space-between
4
-
5 4
         // Tabbed Layout
6
-        w-tabs(v-if="isTab" :items="Object.keys(tabContent)" center fill-bar)
7
-            template(#item-title="{ item }")
5
+        w-tabs(
6
+            :items='Object.keys(tabContent)'
7
+            @input='onTabChanged'
8
+            center
9
+            fill-bar
10
+            v-if='isTab'
11
+        )
12
+            template(#item-title='{ item }')
8 13
                 .w-flex.column.justify-start
9
-                    p(v-if="tabContent[item].matchPerc") {{ tabContent[item].matchPerc }}%
14
+                    p(v-if='tabContent[item].matchPerc') {{ tabContent[item].matchPerc }}%
10 15
                     p(v-else) &nbsp;
11 16
                     p {{ item }}
12 17
             // About Tab
13
-            template(#item-content.1="{ item }")
18
+            template(#item-content.1='{ item }')
14 19
                 .tab--about
15 20
                     p {{ tabContent[item].tab }}
16 21
                     br
17 22
                     p {{ tabContent[item].tab }}
18 23
                     br
19 24
                     hr
20
-            
25
+
21 26
             // Passion Tab
22
-            template(#item-content.2="{ item }")
27
+            template(#item-content.2='{ item }')
23 28
                 .tab--passion
24 29
                     p {{ tabContent[item].tab }}
30
+                    SpiderChart(
31
+                        :labels='aspects.map(label => label.name)'
32
+                        :profile-data='profileScore'
33
+                        :target-data='targetScore'
34
+                        profile-name='lucy'
35
+                        v-if='isTab'
36
+                    )
25 37
 
26 38
             // Aspirations Tab
27
-            template(#item-content.3="{ item }")
39
+            template(#item-content.3='{ item }')
28 40
                 .tab--aspirations
29 41
                     p {{ tabContent[item].tab }}
30 42
 
31 43
             // Skills Tab
32
-            template(#item-content.4="{ item }")
44
+            template(#item-content.4='{ item }')
33 45
                 .tab--skills
34 46
                     p {{ tabContent[item].tab }}
35 47
 
36 48
         // Untabbed Layout
37 49
         ul.w-flex.row.justify-space-between(v-else)
38
-            template(v-for="(item, index) in Object.keys(tabContent)" :key="index")
39
-                li.w-flex.row(v-if="item !== 'about'")
40
-                    w-icon(xl).mr1 mdi mdi-heart
50
+            template(
51
+                :key='index'
52
+                v-for='(item, index) in Object.keys(tabContent)'
53
+            )
54
+                li.w-flex.row(v-if='item !== "about"')
55
+                    w-icon.mr1(xl) mdi mdi-heart
41 56
                     .w-flex.column.justify-start
42 57
                         p {{ tabContent[item].matchPerc }}%
43 58
                         p {{ item }}
44 59
 </template>
45 60
 
46 61
 <script>
62
+import SpiderChart from './SpiderChart.vue'
63
+
47 64
 export default {
65
+    components: { SpiderChart },
48 66
     props: {
67
+        aspects: {
68
+            required: true,
69
+            type: Array,
70
+        },
49 71
         tabContent: {
50 72
             required: true,
51 73
             type: Object,
@@ -61,5 +83,15 @@ export default {
61 83
             default: true,
62 84
         },
63 85
     },
86
+    emits: ['tab-change'],
87
+    data: () => ({
88
+        profileScore: [5.7, 5.2, 4.8, 5.2, 4.9, 4.9],
89
+        targetScore: [5.3, 4.8, 5.7, 4.8, 5.6, 4.8],
90
+    }),
91
+    methods: {
92
+        onTabChanged(tabs) {
93
+            this.$emit('tab-change', tabs)
94
+        },
95
+    },
64 96
 }
65 97
 </script>

+ 0
- 1
frontend/src/views/HomeView.vue Просмотреть файл

@@ -1,6 +1,5 @@
1 1
 <template lang="pug">
2 2
 main.view--home
3
-    
4 3
     article(v-if='cards.length && !loading')
5 4
         ProfileCardList(:pid='pid' :cards='cards' @reload='getCards')
6 5
 

Загрузка…
Отмена
Сохранить