@worksafevictoria/wcl7.5 1.1.0-beta.100 → 1.1.0-beta.102

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,348 @@
1
+ <template>
2
+ <section-group class="paragraph--directory">
3
+ <div v-if="items.length" class="paragraph--directory__records">
4
+ <!-- Filters -->
5
+ <row class="paragraph--directory.hscp-filters">
6
+ <!-- Keyword Filters -->
7
+ <column class="colSearch" md="2" sm="6">
8
+ <label class="visually-hidden" for="search-directory">
9
+ Search by keyword (typed keyword automatically filters below results)
10
+ </label>
11
+ <input type="text" v-model="searchOrg" placeholder="Search organisation" class="search">
12
+ </column>
13
+ <column class="colSearch" md="2" sm="6">
14
+ <label class="visually-hidden" for="search-directory">
15
+ Search by suburb (typed suburb automatically filters below results)
16
+ </label>
17
+ <input type="text" v-model="searchSub" placeholder="Search suburb" class="search">
18
+ </column>
19
+ <!-- Other Filters -->
20
+ <column class="colSearch" md="2" sm="6">
21
+ <select id="filterType" v-model="searchCourse" name="filter" class="selectClass">
22
+ <option class="placeholder" value="" disabled hidden selected>Search course type</option>
23
+ <option value="HSR Initial">HSR Initial</option>
24
+ <option value="HSR Refresher">HSR Refresher</option>
25
+ </select>
26
+ </column>
27
+ <column class="colSearch" md="4" sm="6" style="padding-left: 0px">
28
+ <select id="filterTheme" v-model="searchThemes" name="filter1" class="selectClass">
29
+ <option class="placeholder" value="" disabled hidden selected>Search theme</option>
30
+ <option v-for="(opt, i) in themeOptions" :key="i" :value="opt">
31
+ {{ opt }}
32
+ </option>
33
+ </select>
34
+ </column>
35
+ <column>
36
+ <filter-button
37
+ v-if="!hideReset"
38
+ filter-button="!hideReset"
39
+ :is-reset="true"
40
+ class="filterButton__button filterButton__button--reset"
41
+ @clicked="reset"
42
+ />
43
+ </column>
44
+ </row>
45
+ <!-- HSCP Records -->
46
+ <div class="hscpRecords">
47
+ <template v-for="(item, index) in resultChunks[page]">
48
+ <hscp-record v-if="item.type === 'hscp'" :key="index" :item="item" />
49
+ </template>
50
+ </div>
51
+ <div v-if="filteredRecords.length > 0" align-items="center">
52
+ <pagination
53
+ :total-pages="totalPages"
54
+ :total="totalResults"
55
+ :per-page="perPage"
56
+ :current-page="page + 1"
57
+ @pagechanged="pageChanged($event)"
58
+ />
59
+ </div>
60
+ <h2 v-if="filteredRecords.length === 0">No records found</h2>
61
+ </div>
62
+ </section-group>
63
+
64
+ </template>
65
+
66
+ <script>
67
+
68
+ import hscpRecord from './SingleRecord/index.vue'
69
+ import searchIcon from './../../../../../assets/icons/search.svg?url'
70
+ import SectionGroup from '../../../../Containers/SectionGroup/index.vue'
71
+ import FilterButton from '../../../../Common/FilterButton/index.vue' //Reset
72
+ import Pagination from './pagination.vue'
73
+
74
+ export default {
75
+ name: 'HSCP',
76
+ components: {
77
+ hscpRecord,
78
+ SectionGroup,
79
+ FilterButton,
80
+ Pagination
81
+ },
82
+ data() {
83
+ return {
84
+ searchOrg: '',
85
+ searchSub: '',
86
+ searchCourse: '',
87
+ searchThemes: '',
88
+ filteredItems: null,
89
+ perPage: 10,
90
+ page: 0,
91
+ searchIcon,
92
+ hideReset: true,
93
+ }
94
+ },
95
+ props: {
96
+ items: {
97
+ type: Array,
98
+ required: true,
99
+ },
100
+ },
101
+
102
+ computed: {
103
+
104
+ themeOptions() {
105
+ // Requirement to remove certain values from original courses
106
+ let allThemes = this.flatRecords.map(a => a.courses)
107
+ allThemes = allThemes.join(',')
108
+ allThemes = allThemes.replace(/HSR initial/g, '')
109
+ allThemes = allThemes.replace(/HSR Initial/g, '')
110
+ allThemes = allThemes.replace(/HSR refresher - /g, '')
111
+ allThemes = allThemes.replace(/HSR Refresher - /g, '')
112
+ allThemes = allThemes.replace(/HSR refresher/g, '')
113
+ allThemes = allThemes.replace(/HSR Refresher/g, '')
114
+ allThemes = allThemes.trim()
115
+ allThemes = allThemes.split(',')
116
+ // Remove duplicates
117
+ let s = new Set(allThemes)
118
+ allThemes = [...s]
119
+ // Remove blank values - not completely successful
120
+ allThemes = allThemes.filter(n => n)
121
+
122
+ // Sort the themes
123
+ let sortedThemes = allThemes.sort((a, b) => {
124
+ if (a.trim() < b.trim()) {
125
+ return -1;
126
+ }
127
+ if (a.trim() > b.trim()) {
128
+ return 1;
129
+ }
130
+ return 0;
131
+ })
132
+ if (sortedThemes[0].type === undefined) {
133
+ sortedThemes.splice(0, 1)
134
+ }
135
+ allThemes = sortedThemes
136
+ return allThemes
137
+ },
138
+
139
+ filteredRecords() {
140
+ let results = this.flatRecords
141
+
142
+ if (this.searchOrg.length) {
143
+ this.hideReset = false
144
+ results = results.filter(item => item.title.toLowerCase().includes(this.searchOrg.toLowerCase()))
145
+ }
146
+ if (this.searchSub.length) {
147
+ this.hideReset = false
148
+ results = results.filter(item => item.trainingVenues.toLowerCase().includes(this.searchSub.toLowerCase()))
149
+ }
150
+ if (this.searchCourse.length) {
151
+ this.hideReset = false
152
+ results = results.filter(item => item.courses.toLowerCase().includes(this.searchCourse.toLowerCase()))
153
+ }
154
+ if (this.searchThemes.length) {
155
+ this.hideReset = false
156
+ results = results.filter(item => item.courses.toLowerCase().includes(this.searchThemes.toLowerCase()))
157
+ }
158
+ this.filteredItems = results
159
+ return results
160
+ },
161
+
162
+ flatRecords() {
163
+ let flatRecords = []
164
+ const sortedItems = this.items.sort((a, b) => {
165
+ if (a.Organisation < b.Organisation) {
166
+ return -1;
167
+ }
168
+ if (a.Organisation > b.Organisation) {
169
+ return 1;
170
+ }
171
+ return 0;
172
+ })
173
+ sortedItems.forEach((record) => {
174
+ flatRecords.push({
175
+ type: 'hscp',
176
+ title: record.Organisation,
177
+ fullAddress: record.Main_office_address,
178
+ orgAcronym: record.Organisation_acronym,
179
+ workPhone: record.Work_phone,
180
+ tollfreePhone: record.Toll_free_phone,
181
+ email: record.Email1,
182
+ website: this.formatWebsite(record.Website),
183
+ contact1: record.Contact_1,
184
+ email1: record.Contact_1_Email,
185
+ phone1: record.Contact_1_Phone,
186
+ contact2: record.Contact_2_Name,
187
+ email2: record.Contact_2_Email,
188
+ phone2: record.Contact_2_Phone,
189
+ courses: record.Training_courses.replace(/,$/, ''),
190
+ trainingVenues: record.Training_venues
191
+ })
192
+ })
193
+ return flatRecords
194
+ },
195
+ resultChunks() {
196
+ return this.chunkify(this.filteredItems || this.items, this.perPage)
197
+ },
198
+ noRecordsFound() {
199
+ return this.resultChunks[0].length === 0
200
+ },
201
+ totalResults() {
202
+ return Array.isArray(this.filteredItems) ? this.filteredItems.length : 0
203
+ },
204
+ totalPages() {
205
+ return this.resultChunks.length
206
+ },
207
+ pageResultCount() {
208
+ return this.resultChunks[this.page].length
209
+ }
210
+ },
211
+
212
+ methods: {
213
+
214
+ formatWebsite(url) {
215
+ let startUrl = url.slice(0, 3)
216
+ if (startUrl.toLowerCase() === 'www') {
217
+ return 'http://' + url
218
+ } else {
219
+ return url
220
+ }
221
+ },
222
+
223
+ chunkify(arr, n) {
224
+ if (arr) {
225
+ const chunked = arr.reduce(
226
+ (chunk, val) => {
227
+ if (chunk[chunk.length - 1].length === n) chunk.push([])
228
+ chunk[chunk.length - 1].push(val)
229
+ return chunk
230
+ },
231
+ [[]]
232
+ )
233
+ return chunked
234
+ }
235
+ return [[]]
236
+ },
237
+
238
+ reset() {
239
+ this.hideReset = true
240
+ this.searchOrg = ''
241
+ this.searchCourse = ''
242
+ this.searchSub = ''
243
+ this.searchThemes = ''
244
+ },
245
+
246
+ pageChanged(ev) {
247
+ this.page = ev - 1
248
+ if (this.pageResultCount < this.perPage) {
249
+ console.log('scroll to records')
250
+ this.scrollToRecords()
251
+ }
252
+ },
253
+ scrollToRecords() {
254
+ if (this.$refs.records) {
255
+ const element = this.$refs.records
256
+ const top = element.offsetTop
257
+
258
+ const buttons = [...element.querySelectorAll('button')]
259
+ if (Array.isArray(buttons) && buttons.length > 0) {
260
+ buttons
261
+ .filter((button) => button.getAttribute('aria-expanded') === 'true')
262
+ .forEach((button) => button.click())
263
+
264
+ buttons[0].focus()
265
+ }
266
+
267
+ window.scrollTo({
268
+ top,
269
+ behavior: 'smooth',
270
+ })
271
+ }
272
+ },
273
+ }
274
+ }
275
+ </script>
276
+
277
+ <style lang="scss" scoped>
278
+ @import '../../styles.scss';
279
+ .paragraph--directory.hscp-filters {
280
+
281
+ align-items: center !important;
282
+
283
+ .grid-column {
284
+ display: inline-block;
285
+ width: 25%;
286
+
287
+ @media (max-width: 767px) {
288
+ width: 50%;
289
+ }
290
+
291
+ @media (max-width: 539px) {
292
+ display: block;
293
+ width: 100%;
294
+ float: none;
295
+ margin-bottom: 16px;
296
+ }
297
+ }
298
+ .right {
299
+ float: right;
300
+ position: relative;
301
+ }
302
+
303
+ .records {
304
+ padding: 0;
305
+ margin: 0;
306
+ }
307
+ }
308
+
309
+ .filterButton__button--reset {
310
+ display: inline-block !important;
311
+ float: right;
312
+ }
313
+
314
+ .colSearch {
315
+ padding-right: 16px !important;
316
+ }
317
+
318
+ .hscpRecords {
319
+ padding-top: 16px;
320
+ }
321
+
322
+ .input,
323
+ .button,
324
+ .select,
325
+ .optgroup,
326
+ .selectClass {
327
+ display: inline-block;
328
+ height: 42px;
329
+ border-radius: 8px;
330
+ padding-right: 16px !important;
331
+ border: 1px solid $gray;
332
+ }
333
+
334
+ .search {
335
+ display: inline-block;
336
+ color: $black;
337
+ border: 1px solid $gray;
338
+ border-radius: 8px;
339
+ padding: 10px 12px;
340
+ height: 42px;
341
+ background-image: url('./../../../../../assets/icons/search.svg');
342
+ background-repeat: no-repeat !important;
343
+ background-position: 96% 12px;
344
+ margin-bottom: 16px;
345
+ transition: none;
346
+ }
347
+
348
+ </style>
@@ -0,0 +1,179 @@
1
+ <!-- Copied from pagination used by ISP in the website repository - paginates a list in place instead of search for BE values. -->
2
+ <template>
3
+ <div class="pagination">
4
+ <div>
5
+ {{ `${totalPages} ${pageOrPages} of results` }}
6
+ </div>
7
+ <ul>
8
+ <li v-if="!isFirstPage" class="pagination-item">
9
+ <button type="button" :disabled="isFirstPage" @click="onClickFirstPage">
10
+ First
11
+ </button>
12
+ </li>
13
+ <li v-if="!isFirstPage" class="pagination-item">
14
+ <button
15
+ type="button"
16
+ :disabled="isFirstPage"
17
+ @click="onClickPreviousPage"
18
+ >
19
+ Previous
20
+ </button>
21
+ </li>
22
+ <!-- Visible Buttons Start -->
23
+ <li v-for="(page, i) in pages" :key="i" class="pagination-item">
24
+ <button
25
+ type="button"
26
+ :disabled="page.isDisabled"
27
+ :class="{ active: isPageActive(page.name) }"
28
+ :aria-current="isPageActive(page.name) ? 'page' : false"
29
+ @click="onClickPage(page.name)"
30
+ >
31
+ {{ page.name }}
32
+ </button>
33
+ </li>
34
+ <!-- Visible Buttons End -->
35
+ <li v-if="!isLastPage" class="pagination-item">
36
+ <button type="button" :disabled="isLastPage" @click="onClickNextPage">
37
+ Next
38
+ </button>
39
+ </li>
40
+ <li v-if="!isLastPage" class="pagination-item">
41
+ <button type="button" :disabled="isLastPage" @click="onClickLastPage">
42
+ Last
43
+ </button>
44
+ </li>
45
+ </ul>
46
+ </div>
47
+ </template>
48
+ <script>
49
+ export default {
50
+ props: {
51
+ maxVisibleButtons: {
52
+ type: Number,
53
+ required: false,
54
+ default: 3
55
+ },
56
+ totalPages: {
57
+ type: Number,
58
+ required: true
59
+ },
60
+ total: {
61
+ type: Number,
62
+ required: true
63
+ },
64
+ perPage: {
65
+ type: Number,
66
+ required: true
67
+ },
68
+ currentPage: {
69
+ type: Number,
70
+ required: true
71
+ }
72
+ },
73
+ computed: {
74
+ startPage() {
75
+ // When on the first page
76
+ if (this.currentPage === 1) {
77
+ return 1
78
+ }
79
+ // When on the last page
80
+ if (this.currentPage === this.totalPages) {
81
+ return this.totalPages - 1
82
+ }
83
+ // When inbetween
84
+ return this.currentPage - 1
85
+ },
86
+ pages() {
87
+ const range = []
88
+ for (
89
+ let i = this.startPage;
90
+ i <=
91
+ Math.min(this.startPage + this.maxVisibleButtons - 1, this.totalPages);
92
+ i++
93
+ ) {
94
+ range.push({
95
+ name: i,
96
+ isDisabled: i === this.currentPage
97
+ })
98
+ }
99
+ return range
100
+ },
101
+ isFirstPage() {
102
+ return this.currentPage === 1
103
+ },
104
+ isLastPage() {
105
+ return this.currentPage === this.totalPages
106
+ },
107
+ pageOrPages() {
108
+ return this.totalPages > 1 ? 'pages' : 'page'
109
+ }
110
+ },
111
+ methods: {
112
+ onClickFirstPage() {
113
+ this.$emit('pagechanged', 1)
114
+ },
115
+ onClickPreviousPage() {
116
+ this.$emit('pagechanged', this.currentPage - 1)
117
+ },
118
+ onClickPage(page) {
119
+ this.$emit('pagechanged', page)
120
+ },
121
+ onClickNextPage() {
122
+ this.$emit('pagechanged', this.currentPage + 1)
123
+ },
124
+ onClickLastPage() {
125
+ this.$emit('pagechanged', this.totalPages)
126
+ },
127
+ isPageActive(page) {
128
+ return this.currentPage === page
129
+ }
130
+ }
131
+ }
132
+ </script>
133
+
134
+ <style lang="scss" scoped>
135
+ @import '../../../../../includes/scss/all.scss';
136
+
137
+ .pagination {
138
+ display: flex;
139
+ align-items: center;
140
+ justify-content: center;
141
+ flex-direction: column;
142
+ ul {
143
+ display: flex;
144
+ margin: 16px 0;
145
+ padding: 0;
146
+ }
147
+
148
+ li {
149
+ list-style: none;
150
+ padding: 0;
151
+ margin-right: 6px;
152
+ margin-left: 0;
153
+ margin-top: 0;
154
+ margin-bottom: 0;
155
+
156
+ button {
157
+ background: $white;
158
+ color: $black;
159
+ border: 1px solid $gray;
160
+ padding: 10px 12px;
161
+ font-weight: normal;
162
+ border-radius: 8px;
163
+ cursor: pointer;
164
+
165
+ &:hover {
166
+ background: $lightgray;
167
+ }
168
+ &:disabled,
169
+ &[disabled] {
170
+ background: $black;
171
+ color: $white;
172
+ font-weight: 700;
173
+ border: 1px solid transparent;
174
+ cursor: default;
175
+ }
176
+ }
177
+ }
178
+ }
179
+ </style>
@@ -55,5 +55,5 @@ export default {
55
55
  }
56
56
  </script>
57
57
  <style lang="scss" scoped>
58
- @import '../styles.scss';
58
+ @import '../../styles.scss';
59
59
  </style>
@@ -84,5 +84,5 @@ export default {
84
84
  }
85
85
  </script>
86
86
  <style lang="scss" scoped>
87
- @import '../styles.scss';
87
+ @import '../../styles.scss';
88
88
  </style>
@@ -55,5 +55,5 @@ export default {
55
55
  }
56
56
  </script>
57
57
  <style lang="scss" scoped>
58
- @import '../styles.scss';
58
+ @import '../../styles.scss';
59
59
  </style>
@@ -0,0 +1,47 @@
1
+ import Records from './index.vue'
2
+ import { hscpData } from '../../../../mock/course-provider'
3
+
4
+ const hscpOptions =
5
+ {
6
+ field_directory_exposefilters: 'full',
7
+ field_directory_rows: 15,
8
+ field_directory_type: 'hscp'
9
+ }
10
+
11
+ const hscpTaxonomies = [
12
+ {
13
+ name: 'Service Type',
14
+ record_id: 'record_hscp_course',
15
+ terms: ['HSR Iniitial', 'HSR Refresher']
16
+ }
17
+ ]
18
+
19
+ export default {
20
+ title: 'Paragraphs/Directory/Records',
21
+ component: Records,
22
+ tags: ['autodocs'],
23
+ data() {
24
+ return {
25
+ hscpData
26
+ }
27
+ },
28
+ argTypes: {
29
+ fetchRecords: {
30
+ control: 'function',
31
+ table: { disable: true }
32
+ },
33
+ fetchFilters: {
34
+ control: 'function',
35
+ table: { disable: true }
36
+ }
37
+ },
38
+ }
39
+
40
+ export const CourseProvider = {
41
+ args: {
42
+ options: hscpOptions,
43
+ items: hscpData,
44
+ taxonomies: hscpTaxonomies,
45
+ showFilters: true
46
+ }
47
+ }
@@ -2,13 +2,8 @@
2
2
  <div v-if="items.length" class="paragraph--directory__records">
3
3
  <template v-for="(item, index) in flatRecords">
4
4
  <prs-record v-if="item.type === 'prs'" :key="index" :item="item" />
5
- <isp-record
6
- v-if="item.type === 'isp'"
7
- :key="index"
8
- :item="item"
9
- :location="baseLocation"
10
- />
11
5
  <hscp-record v-if="item.type === 'hscp'" :key="index" :item="item" />
6
+ <isp-record v-if="item.type === 'isp'" :key="index" :item="item" :location="baseLocation" />
12
7
  <cj-record v-if="item.type === 'cj'" :key="index" :item="item" />
13
8
  </template>
14
9
  </div>
@@ -17,14 +12,14 @@
17
12
  import PrsRecord from './PRS/index.vue'
18
13
  import IspRecord from './ISP/index.vue'
19
14
  import CjRecord from './CJ/index.vue'
20
- import HscpRecord from './HSCP/index.vue'
15
+ import HscpRecord from './../HSCP/Records/SingleRecord/index.vue'
21
16
 
22
17
  export default {
23
18
  components: {
24
19
  PrsRecord,
25
20
  IspRecord,
26
21
  CjRecord,
27
- HscpRecord,
22
+ HscpRecord
28
23
  },
29
24
  props: {
30
25
  items: {
@@ -147,35 +142,23 @@ export default {
147
142
  },
148
143
  })
149
144
  }
150
- if (record.record_type === 'hscp') {
151
- let {
152
- record_id,
153
- data: {
154
- attributes: {
155
- title,
156
- hscp: {
157
- fulladdress,
158
- workphone,
159
- tollfreephone,
160
- email,
161
- website,
162
- courses,
163
- companyid,
164
- } = {},
165
- } = {},
166
- } = {},
167
- } = record
145
+ if (record.type === 'hscp') {
168
146
  flatRecords.push({
169
- id: record_id,
170
147
  type: 'hscp',
171
- title,
172
- fulladdress,
173
- workphone,
174
- tollfreephone,
175
- email,
176
- website,
177
- courses,
178
- companyid,
148
+ title: record.title,
149
+ fullAddress: record.fullAddress,
150
+ workPhone: record.workPhone,
151
+ tollfreePhone: record.tollfreePhone,
152
+ email: record.email,
153
+ website: record.website,
154
+ contact1: record.contact1,
155
+ email1: record.email1,
156
+ phone1: record.phone1,
157
+ contact2: record.contact2,
158
+ email2: record.email2,
159
+ phone2: record.phone2,
160
+ courses: record.courses,
161
+ trainingVenues: record.trainingVenues
179
162
  })
180
163
  }
181
164
  if (record.record_type === 'cj') {