Skip to content

Commit 4ba5011

Browse files
authored
Merge pull request #6045 from usu/feat/activity-list-print-react
feat(print): activity list implementation for react print
2 parents a2ab70c + e49df4f commit 4ba5011

File tree

14 files changed

+2985
-927
lines changed

14 files changed

+2985
-927
lines changed

frontend/eslint.config.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ export default [
8181
'error',
8282
{
8383
ignoreKeysRegex:
84-
'^(global|entity|contentNode\\.[a-z][a-zA-Z]+|print\\.(global|activity|cover|picasso|program|config|summary|toc))\\..+',
84+
'^(global|entity|contentNode\\.[a-z][a-zA-Z]+|print\\.(global|activity|cover|picasso|program|config|summary|toc|activityList))\\..+',
8585
translationKeyPropRegex: '[a-zA-Z0-9]-i18n-key$',
8686
},
8787
],

pdf/eslint.config.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ export default [
7777
'error',
7878
{
7979
ignoreKeysRegex:
80-
'^(global|entity|contentNode\\.[a-z][a-zA-Z]+|print\\.(global|activity|cover|picasso|program|config|summary|toc))\\..+',
80+
'^(global|entity|contentNode\\.[a-z][a-zA-Z]+|print\\.(global|activity|cover|picasso|program|config|summary|toc|activityList))\\..+',
8181
translationKeyPropRegex: '[a-zA-Z0-9]-i18n-key$',
8282
},
8383
],

pdf/src/CampPrint.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import Story from '@/campPrint/summary/Story.vue'
2727
import SafetyConsiderations from '@/campPrint/summary/SafetyConsiderations.vue'
2828
import Program from '@/campPrint/program/Program.vue'
2929
import Activity from '@/campPrint/activity/Activity.vue'
30+
import ActivityList from '@/campPrint/activityList/ActivityList.vue'
3031
import { wordHyphenation } from '@react-pdf/textkit'
3132
3233
const originalHyphenationCallback = wordHyphenation()
@@ -47,6 +48,7 @@ export default {
4748
Activity,
4849
Story,
4950
SafetyConsiderations,
51+
ActivityList,
5052
}
5153
},
5254
},
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<template>
2+
<Page :id="id" class="page">
3+
<ActivityListPeriod
4+
v-for="period in periods"
5+
:id="id"
6+
:period="period"
7+
:config="config"
8+
:content-type-names="['LearningObjectives', 'LearningTopics', 'Checklist']"
9+
/>
10+
</Page>
11+
</template>
12+
<script>
13+
import PdfComponent from '@/PdfComponent.js'
14+
import ActivityListPeriod from './ActivityListPeriod.vue'
15+
16+
export default {
17+
name: 'ActivityList',
18+
components: { ActivityListPeriod },
19+
extends: PdfComponent,
20+
props: {
21+
content: { type: Object, required: true },
22+
config: { type: Object, required: true },
23+
},
24+
computed: {
25+
periods() {
26+
return this.content.options.periods.map((periodUri) => this.api.get(periodUri))
27+
},
28+
},
29+
}
30+
</script>
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<template>
2+
<Text
3+
:id="`${id}-${period.id}`"
4+
:bookmark="{ title: title + ': ' + period.description, fit: true }"
5+
class="activity-list-period-title"
6+
>{{ title }}: {{ period.description }}</Text
7+
>
8+
<ActivityListScheduleEntry
9+
v-for="scheduleEntry in scheduleEntries"
10+
:id="id"
11+
:schedule-entry="scheduleEntry"
12+
:content-types="contentTypes"
13+
:content-nodes="contentNodes"
14+
/>
15+
</template>
16+
<script>
17+
import PdfComponent from '@/PdfComponent.js'
18+
import ActivityListScheduleEntry from './ActivityListScheduleEntry.vue'
19+
import camelCase from 'lodash/camelCase.js'
20+
21+
export default {
22+
name: 'ActivityListPeriod',
23+
components: { ActivityListScheduleEntry },
24+
extends: PdfComponent,
25+
props: {
26+
period: { type: Object, required: true },
27+
contentTypeNames: { type: Array, required: true },
28+
config: { type: Object, required: true },
29+
},
30+
computed: {
31+
scheduleEntries() {
32+
return this.period.scheduleEntries().items
33+
},
34+
allContentTypes() {
35+
return this.api.get('/content_types').items
36+
},
37+
contentTypes() {
38+
return this.contentTypeNames.map((contentTypeName) =>
39+
this.allContentTypes.find((contentType) => contentType.name === contentTypeName)
40+
)
41+
},
42+
contentNodes() {
43+
return this.contentTypes.map((contentType) =>
44+
this.period.contentNodes().items.filter((contentNode) => {
45+
return contentNode.contentType()._meta.self === contentType._meta.self
46+
})
47+
)
48+
},
49+
title() {
50+
return this.$tc('print.activityList.title')
51+
},
52+
},
53+
methods: { camelCase },
54+
}
55+
</script>
56+
<pdf-style>
57+
.activity-list-period-title {
58+
font-size: 10pt;
59+
font-weight: bold;
60+
text-align: center;
61+
}
62+
</pdf-style>
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<template>
2+
<ScheduleEntryTitle :schedule-entry="scheduleEntry" :show-header="false" />
3+
4+
<View style="margin-top: 10pt; padding-bottom: 20pt; font-size: 10pt">
5+
<ContentNode
6+
v-for="contentNode in contentNodeEntries"
7+
:key="contentNode.id"
8+
:content-node="contentNode"
9+
/>
10+
</View>
11+
</template>
12+
<script>
13+
import PdfComponent from '@/PdfComponent.js'
14+
import ScheduleEntryTitle from '../scheduleEntry/ScheduleEntryTitle.vue'
15+
import ContentNode from '../scheduleEntry/contentNode/ContentNode.vue'
16+
import sortBy from 'lodash/sortBy.js'
17+
18+
export default {
19+
name: 'ScheduleEntry',
20+
components: { ContentNode, ScheduleEntryTitle },
21+
extends: PdfComponent,
22+
props: {
23+
scheduleEntry: { type: Object, required: true },
24+
contentTypes: { type: Array, required: true },
25+
contentNodes: { type: Array, required: true },
26+
},
27+
computed: {
28+
contentNodeEntries() {
29+
return sortBy(
30+
this.contentNodes.map((contentNodeList) =>
31+
contentNodeList.filter(
32+
(contentNode) =>
33+
contentNode.root()._meta.self ===
34+
this.scheduleEntry.activity().rootContentNode()._meta.self
35+
)
36+
),
37+
['parent', 'slot', 'position']
38+
).flat()
39+
},
40+
},
41+
}
42+
</script>
43+
<pdf-style>
44+
</pdf-style>
Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
<template>
2-
<Text class="content-node-instance-name">{{ instanceName }}</Text>
2+
<View class="content-node-title">
3+
<Text class="content-node-instance-name">{{ instanceName }}</Text>
4+
<Text v-if="contentNode.instanceName" class="content-type-name">{{
5+
contentTypeName
6+
}}</Text>
7+
</View>
38
</template>
49
<script>
510
import PdfComponent from '@/PdfComponent.js'
@@ -13,20 +18,32 @@ export default {
1318
},
1419
computed: {
1520
instanceName() {
16-
return (
17-
this.contentNode.instanceName ||
18-
this.$tc(`contentNode.${camelCase(this.contentNode.contentTypeName)}.name`)
19-
)
21+
return this.contentNode.instanceName || this.contentTypeName
22+
},
23+
contentTypeName() {
24+
return this.$tc(`contentNode.${camelCase(this.contentNode.contentTypeName)}.name`)
2025
},
2126
},
2227
}
2328
</script>
2429
<pdf-style>
30+
.content-node-title {
31+
border-bottom: 1.5pt solid black;
32+
margin-bottom: 1pt;
33+
display: flex;
34+
flex-direction: row;
35+
justify-content: space-between;
36+
align-items: baseline;
37+
}
2538
.content-node-instance-name {
39+
flex-grow: 1;
2640
font-weight: bold;
2741
font-size: 11pt;
2842
padding-bottom: 3pt;
29-
border-bottom: 1.5pt solid black;
30-
margin-bottom: 1pt;
43+
}
44+
.content-type-name {
45+
font-size:8pt;
46+
font-weight:normal;
47+
color:grey;
3148
}
3249
</pdf-style>
Lines changed: 3 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,12 @@
11
<template>
2-
<View :wrap="false" :min-presence-ahead="75">
3-
<View
4-
class="schedule-entry-header-title"
5-
:style="{ borderBottomColor: activity.category().color }"
6-
>
7-
<View :id="`scheduleEntry_${scheduleEntry.id}`" class="schedule-entry-title">
8-
<CategoryLabel
9-
:category="activity.category()"
10-
class="schedule-entry-category-label"
11-
/>
12-
<Text :id="id" :bookmark="bookmarkTitle" class="schedule-entry-number-and-title">
13-
{{ scheduleEntry.number }} {{ activity.title }}
14-
</Text>
15-
</View>
16-
<Text class="schedule-entry-date">{{ startAt }} - {{ endAt }}</Text>
17-
</View>
18-
<View v-if="showHeader" class="schedule-entry-header">
19-
<View class="schedule-entry-header-metadata">
20-
<View class="schedule-entry-header-metadata-entry"
21-
><Text v-if="activity.location" class="schedule-entry-header-metadata-label"
22-
>{{ $tc('entity.activity.fields.location') }}:</Text
23-
><Text>{{ activity.location }}</Text></View
24-
>
25-
</View>
26-
<View class="schedule-entry-header-divider" />
27-
<View class="schedule-entry-header-metadata">
28-
<View class="schedule-entry-header-metadata-entry">
29-
<Text
30-
v-if="activity.activityResponsibles().items.length"
31-
class="schedule-entry-header-metadata-label"
32-
>{{ $tc('entity.activity.fields.responsible') }}:</Text
33-
>
34-
<Responsibles :activity="activity" style="max-width: 200pt" />
35-
</View>
36-
</View>
37-
</View>
38-
</View>
2+
<ScheduleEntryTitle :schedule-entry="scheduleEntry" />
393
<View style="padding-bottom: 20pt; font-size: 10pt">
404
<ContentNode :content-node="activity.rootContentNode()" />
415
</View>
426
</template>
437
<script>
448
import PdfComponent from '@/PdfComponent.js'
45-
import CategoryLabel from '../CategoryLabel.vue'
46-
import Responsibles from '../Responsibles.vue'
9+
import ScheduleEntryTitle from './ScheduleEntryTitle.vue'
4710
import ContentNode from './contentNode/ContentNode.vue'
4811
import { setContentNodeComponent as setContentNodeComponentColumn } from './contentNode/ColumnLayout.vue'
4912
import { setContentNodeComponent as setContentNodeComponentDefault } from './contentNode/ResponsiveLayout.vue'
@@ -53,7 +16,7 @@ setContentNodeComponentDefault(ContentNode)
5316
5417
export default {
5518
name: 'ScheduleEntry',
56-
components: { Responsibles, CategoryLabel, ContentNode },
19+
components: { ScheduleEntryTitle, ContentNode },
5720
extends: PdfComponent,
5821
props: {
5922
scheduleEntry: { type: Object, required: true },
@@ -62,89 +25,8 @@ export default {
6225
activity() {
6326
return this.scheduleEntry.activity()
6427
},
65-
bookmarkTitle() {
66-
return [
67-
this.activity.category().short,
68-
this.scheduleEntry.number,
69-
this.activity.title,
70-
]
71-
.filter((entry) => entry)
72-
.join(' ')
73-
},
74-
start() {
75-
return this.$date.utc(this.scheduleEntry.start)
76-
},
77-
end() {
78-
return this.$date.utc(this.scheduleEntry.end)
79-
},
80-
startAt() {
81-
return this.start.format('ddd l LT')
82-
},
83-
endAt() {
84-
return this.start.format('ddd l') === this.end.format('ddd l')
85-
? this.end.format('LT')
86-
: this.end.format('ddd l LT')
87-
},
88-
showHeader() {
89-
return (
90-
this.activity.location.length || this.activity.activityResponsibles().items.length
91-
)
92-
},
9328
},
9429
}
9530
</script>
9631
<pdf-style>
97-
.schedule-entry-header-title {
98-
display: flex;
99-
flex-direction: row;
100-
justify-content: space-between;
101-
align-items: baseline;
102-
padding-bottom: 2pt;
103-
border-bottom: 2pt solid #aaaaaa;
104-
}
105-
.schedule-entry-title {
106-
flex-grow: 1;
107-
display: flex;
108-
flex-direction: row;
109-
font-size: 14;
110-
font-weight: semibold;
111-
}
112-
.schedule-entry-category-label {
113-
margin: 4pt 0;
114-
font-size: 12pt;
115-
}
116-
.schedule-entry-number-and-title {
117-
margin: 4pt 4pt;
118-
max-width: 345pt;
119-
}
120-
.schedule-entry-date {
121-
font-size: 11pt;
122-
}
123-
.schedule-entry-header {
124-
display: flex;
125-
flex-direction: row;
126-
justify-content: space-between;
127-
border-bottom: 0.5pt solid black;
128-
font-size: 10pt;
129-
margin-bottom: 10pt;
130-
}
131-
.schedule-entry-header-divider {
132-
border-left: 0.5pt solid black;
133-
margin-left: 3.5pt;
134-
padding-left: 5pt
135-
}
136-
.schedule-entry-header-metadata {
137-
width: 50%;
138-
padding: 2pt 0;
139-
}
140-
.schedule-entry-header-metadata-entry {
141-
flex-direction: row;
142-
align-items: flex-start;
143-
column-gap: 6pt;
144-
}
145-
.schedule-entry-header-metadata-label {
146-
font-weight: semibold;
147-
flex-shrink: 0;
148-
flex-grow: 0;
149-
}
15032
</pdf-style>

0 commit comments

Comments
 (0)