bfg-common 1.4.390 → 1.4.393

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.
@@ -1,4 +1,5 @@
1
1
  import type { UI_I_FeedbackForm } from '~/components/common/feedback/lib/models/interfaces'
2
+ // import type { UI_I_FeedbackCanvasOptions } from '~/components/common/layout/theHeader/feedback/new/lib/models/interfaces'
2
3
  export const feedbackDefaultFormFunc = (): UI_I_FeedbackForm => {
3
4
  return {
4
5
  description: '',
@@ -7,3 +8,10 @@ export const feedbackDefaultFormFunc = (): UI_I_FeedbackForm => {
7
8
  image: '', // base64
8
9
  }
9
10
  }
11
+
12
+ // export const feedbackCanvasDefaultOptions = (): UI_I_FeedbackCanvasOptions => {
13
+ // return {
14
+ // isAnnotateImage: false,
15
+ // hasTakeScreenshot: false,
16
+ // }
17
+ // }
@@ -2,40 +2,46 @@
2
2
  <Teleport to="body">
3
3
  <ui-modal
4
4
  show
5
- width="560px"
5
+ :width="!options.isAnnotateImage ? '560px' : '880px'"
6
6
  test-id="feedback-modal"
7
- :title="localization.common.sendFeedback"
7
+ :title="title"
8
8
  class="feedback"
9
9
  @hide="onHideModal"
10
10
  >
11
11
  <template #content>
12
12
  <ui-modal-block-standard>
13
- <common-layout-the-header-feedback-new-subtitle />
13
+ <template v-if="!options.isAnnotateImage">
14
+ <common-layout-the-header-feedback-new-subtitle />
14
15
 
15
- <common-layout-the-header-feedback-new-tabs
16
- v-model="selectedTab"
17
- class="metrics-tabs"
18
- />
19
-
20
- <div
21
- v-if="selectedTab === 'light-bulb'"
22
- class="feedback__visit-portal"
23
- >
24
- {{ localization.common.useOurExternalIdeasPortal }}
25
- </div>
26
-
27
- <template v-else>
28
- <common-layout-the-header-feedback-new-description
29
- v-model="feedbackForm.description"
30
- v-model:is-valid="isValidForm"
31
- :selected-tab="selectedTab"
16
+ <common-layout-the-header-feedback-new-tabs
17
+ v-model="selectedTab"
18
+ class="metrics-tabs"
32
19
  />
33
20
 
34
- <common-layout-the-header-feedback-new-email
35
- v-model="feedbackForm.email"
36
- />
21
+ <div
22
+ v-if="selectedTab === 'light-bulb'"
23
+ class="feedback__visit-portal"
24
+ >
25
+ {{ localization.common.useOurExternalIdeasPortal }}
26
+ </div>
27
+ </template>
37
28
 
38
- <common-layout-the-header-feedback-new-additional-details />
29
+ <template v-if="selectedTab !== 'light-bulb'">
30
+ <template v-if="!options.isAnnotateImage">
31
+ <common-layout-the-header-feedback-new-description
32
+ v-model="feedbackForm.description"
33
+ v-model:is-valid="isValidForm"
34
+ :selected-tab="selectedTab"
35
+ />
36
+
37
+ <common-layout-the-header-feedback-new-email
38
+ v-model="feedbackForm.email"
39
+ />
40
+ </template>
41
+
42
+ <common-layout-the-header-feedback-new-additional-details
43
+ v-model="options"
44
+ />
39
45
  </template>
40
46
  </ui-modal-block-standard>
41
47
  </template>
@@ -57,7 +63,7 @@
57
63
  <ui-button
58
64
  test-id="feedback-modal-submit-btn"
59
65
  size="md"
60
- :disabled="!selectedTab"
66
+ :disabled="isDisabledButton"
61
67
  min-width="96px"
62
68
  @click="onSubmit"
63
69
  >
@@ -80,6 +86,7 @@
80
86
  import type { UI_I_Localization } from '~/lib/models/interfaces'
81
87
  import type { UI_I_FeedbackForm } from '~/components/common/feedback/lib/models/interfaces'
82
88
  import type { UI_T_FeedbackTab } from '~/components/common/layout/theHeader/feedback/new/tabs/lib/models/types'
89
+ import type { UI_I_FeedbackCanvasOptions } from '~/components/common/layout/theHeader/feedback/new/lib/models/interfaces'
83
90
 
84
91
  const feedbackForm = defineModel<UI_I_FeedbackForm>({ required: true })
85
92
  const emits = defineEmits<{
@@ -89,17 +96,40 @@ const emits = defineEmits<{
89
96
 
90
97
  const localization = computed<UI_I_Localization>(() => useLocal())
91
98
 
92
- const isValidForm = ref<boolean>(true)
93
99
  const selectedTab = ref<UI_T_FeedbackTab>()
100
+ const isValidForm = ref<boolean>(true)
101
+ const options = ref<UI_I_FeedbackCanvasOptions>({
102
+ isAnnotateImage: false,
103
+ hasTakeScreenshot: false,
104
+ })
105
+
106
+ const title = computed<string>(() => {
107
+ const { common, feedback } = localization.value
108
+
109
+ return !options.value.isAnnotateImage
110
+ ? common.sendFeedback
111
+ : options.value.hasTakeScreenshot
112
+ ? feedback.annotateScreenshot
113
+ : feedback.annotateImage
114
+ })
115
+ const modalFooterButtonNames = computed<string>(() => {
116
+ const { visitIdeasPortal, send, save } = localization.value.common
117
+
118
+ return options.value.isAnnotateImage
119
+ ? save
120
+ : selectedTab.value === 'light-bulb'
121
+ ? visitIdeasPortal
122
+ : send
123
+ })
94
124
 
95
- const modalFooterButtonNames = computed(() => {
96
- return selectedTab.value === 'light-bulb'
97
- ? localization.value.common.visitIdeasPortal
98
- : localization.value.common.send
125
+ const isDisabledButton = computed<boolean>(() => {
126
+ return !options.value.isAnnotateImage && !selectedTab.value
99
127
  })
100
128
 
101
129
  const onHideModal = (): void => {
102
- emits('hide')
130
+ !options.value.isAnnotateImage
131
+ ? emits('hide')
132
+ : (options.value.isAnnotateImage = false)
103
133
  }
104
134
  const onSubmit = (): void => {
105
135
  if (selectedTab.value === 'light-bulb') {
@@ -1,16 +1,21 @@
1
1
  <template>
2
2
  <div class="additional-details">
3
- <common-layout-the-header-feedback-new-additional-details-headline />
3
+ <template v-if="!optionsModel.isAnnotateImage">
4
+ <common-layout-the-header-feedback-new-additional-details-headline />
4
5
 
5
- <ui-alert
6
- v-if="hasTakeScreenshot"
7
- test-id="additional-details-info-alert"
8
- :messages="[localization.common.screenshotQualityMayVary]"
9
- type="info"
10
- class="additional-details__alert"
11
- ></ui-alert>
6
+ <ui-alert
7
+ v-if="optionsModel.hasTakeScreenshot"
8
+ test-id="additional-details-info-alert"
9
+ :messages="[localization.common.screenshotQualityMayVary]"
10
+ type="info"
11
+ class="additional-details__alert"
12
+ ></ui-alert>
13
+ </template>
12
14
 
13
- <div v-if="!hasTakeScreenshot" class="flex gap-4 button-container">
15
+ <div
16
+ v-if="!optionsModel.hasTakeScreenshot"
17
+ class="flex gap-4 button-container"
18
+ >
14
19
  <ui-button
15
20
  test-id="feedback-take-screenshot-btn"
16
21
  size="md"
@@ -57,11 +62,85 @@
57
62
  </ui-button>
58
63
  </div>
59
64
 
65
+ <div v-if="optionsModel.isAnnotateImage" class="drawer-btn-container">
66
+ <div>
67
+ <ui-button
68
+ test-id="feedback-use-red-marker-button"
69
+ size="sm"
70
+ type="default"
71
+ variant="outline"
72
+ class="btn marker"
73
+ @click="onUseRedMarker"
74
+ >
75
+ <ui-icon
76
+ name="marker"
77
+ width="16"
78
+ height="16"
79
+ class="feedback__btn-icon"
80
+ />
81
+ {{ localization.common.useRedMarker }}
82
+ </ui-button>
83
+
84
+ <ui-button
85
+ test-id="feedback-use-grey-marker-button"
86
+ size="sm"
87
+ type="default"
88
+ variant="outline"
89
+ class="btn eraser"
90
+ @click="onUseGrayEraser"
91
+ >
92
+ <ui-icon
93
+ name="grey-eraser"
94
+ width="16"
95
+ height="16"
96
+ class="feedback__btn-icon"
97
+ />
98
+ {{ localization.common.useGrayEraser }}
99
+ </ui-button>
100
+ <ui-button
101
+ test-id="feedback-undo-button"
102
+ size="sm"
103
+ type="default"
104
+ variant="outline"
105
+ class="btn undo"
106
+ @click="onUndoLast"
107
+ >
108
+ <ui-icon
109
+ name="reset"
110
+ width="16"
111
+ height="16"
112
+ class="feedback__btn-icon"
113
+ />
114
+ {{ localization.common.undo }}
115
+ </ui-button>
116
+ </div>
117
+
118
+ <ui-button
119
+ test-id="feedback-clear-all-button"
120
+ size="sm"
121
+ type="default"
122
+ variant="outline"
123
+ class="btn clear-all"
124
+ @click="clearAll"
125
+ >
126
+ <ui-icon
127
+ name="delete"
128
+ width="16"
129
+ height="16"
130
+ class="feedback__btn-icon"
131
+ />
132
+ {{ localization.common.clearAll }}
133
+ </ui-button>
134
+ </div>
135
+
60
136
  <div
61
137
  id="feedbackImgWrap"
62
138
  ref="feedbackImgWrap"
63
139
  class="preview-container"
64
- :class="!hasTakeScreenshot && 'disabled'"
140
+ :class="{
141
+ disabled: !optionsModel.hasTakeScreenshot,
142
+ annotate: optionsModel.isAnnotateImage,
143
+ }"
65
144
  >
66
145
  <div class="preview-container__backdrop">
67
146
  <div>
@@ -71,6 +150,7 @@
71
150
  type="default"
72
151
  variant="outline"
73
152
  class=""
153
+ @click="onAnnotateImage"
74
154
  >
75
155
  <ui-icon
76
156
  name="annotate-icon"
@@ -112,14 +192,15 @@
112
192
  <script lang="ts" setup>
113
193
  import html2canvas from 'html2canvas'
114
194
  import type { UI_I_Localization } from '~/lib/models/interfaces'
195
+ import type { UI_I_FeedbackCanvasOptions } from '~/components/common/layout/theHeader/feedback/new/lib/models/interfaces'
115
196
 
116
- const localization = computed<UI_I_Localization>(() => useLocal())
117
-
197
+ const optionsModel = defineModel<UI_I_FeedbackCanvasOptions>({ required: true })
118
198
  const emits = defineEmits<{
119
199
  (event: 'screen-shot', value: any): void
120
200
  }>()
121
201
 
122
- const hasTakeScreenshot = ref<boolean>(false)
202
+ const localization = computed<UI_I_Localization>(() => useLocal())
203
+
123
204
  const isFileLoad = ref(null)
124
205
  const feedbackImgWrap = ref()
125
206
  const feedbackImg = ref()
@@ -129,13 +210,15 @@ const memoryParentMain = ref<string>('')
129
210
  const drawingArray: any = []
130
211
  // const indexArray = 0 // index of feedbackImg itself
131
212
  const indexArray = ref<number>(0) // index of feedbackImg itself
132
- // let drawColor = ''
133
- // let drawWidth = ''
213
+ let isDrawing = false
214
+ let startDrawingX: number | null = null
215
+ let startDrawingY: number | null = null
216
+ let drawColor = ''
217
+ let drawWidth = ''
134
218
 
135
219
  const onTakeScreenshot = (): void => {
136
- hasTakeScreenshot.value = true
220
+ optionsModel.value.hasTakeScreenshot = true
137
221
  const value = {
138
- hasTakeScreenshot: true,
139
222
  width: window.outerWidth + 'px',
140
223
  }
141
224
 
@@ -177,7 +260,7 @@ const onTakeScreenshot = (): void => {
177
260
  })
178
261
  }
179
262
  const onUploadFile = (): void => {
180
- hasTakeScreenshot.value = true
263
+ optionsModel.value.hasTakeScreenshot = true
181
264
  if (!isFileLoad.value) return
182
265
 
183
266
  const isFileRead = new FileReader()
@@ -204,7 +287,6 @@ const onUploadFile = (): void => {
204
287
  )
205
288
  )
206
289
  const value = {
207
- hasTakeScreenshot: true,
208
290
  width: window.outerWidth + 'px',
209
291
  }
210
292
  emits('screen-shot', value)
@@ -222,8 +304,65 @@ const onUploadFile = (): void => {
222
304
  }
223
305
  }
224
306
 
307
+ const start = (event: MouseEvent): void => {
308
+ if (!drawColor) return
309
+ const context = feedbackImg.value.getContext('2d')
310
+ const canvasCoordinates = feedbackImg.value.getBoundingClientRect()
311
+ startDrawingX = event.pageX - canvasCoordinates.left
312
+ startDrawingY = event.pageY - canvasCoordinates.top
313
+ isDrawing = true
314
+ context.beginPath()
315
+ context.moveTo(
316
+ event.pageX - canvasCoordinates.left,
317
+ event.pageY - canvasCoordinates.top
318
+ )
319
+ event.preventDefault()
320
+ }
321
+ const draw = (event: MouseEvent): void => {
322
+ if (!drawColor) return
323
+ const context = feedbackImg.value.getContext('2d')
324
+ const canvasCoordinates = feedbackImg.value.getBoundingClientRect()
325
+ if (!isDrawing) return
326
+ context.lineTo(
327
+ event.pageX - canvasCoordinates.left,
328
+ event.pageY - canvasCoordinates.top
329
+ )
330
+ context.strokeStyle = drawColor
331
+ context.lineWidth = drawWidth
332
+ context.lineCap = 'round'
333
+ context.lineJoin = 'round'
334
+ context.stroke()
335
+ event.preventDefault()
336
+ }
337
+
338
+ const stop = (event: MouseEvent): void => {
339
+ if (!drawColor) return
340
+
341
+ const context = feedbackImg.value.getContext('2d')
342
+ const canvasCoordinates = feedbackImg.value.getBoundingClientRect()
343
+ if (!isDrawing) return
344
+
345
+ context.stroke()
346
+ context.closePath()
347
+ isDrawing = false
348
+ event.preventDefault()
349
+ if (
350
+ startDrawingX !== event.pageX - canvasCoordinates.left &&
351
+ startDrawingY !== event.pageY - canvasCoordinates.top
352
+ ) {
353
+ drawingArray.push(
354
+ context.getImageData(
355
+ 0,
356
+ 0,
357
+ feedbackImg.value.width,
358
+ feedbackImg.value.height
359
+ )
360
+ )
361
+ indexArray.value += 1
362
+ }
363
+ }
225
364
  const onRemoveScreenshot = (): void => {
226
- hasTakeScreenshot.value = false
365
+ optionsModel.value.hasTakeScreenshot = false
227
366
  const parentMain = document.getElementById('feedbackId')
228
367
  const parentModalDialog = document.getElementById('feedback-modal-dialog-Id')
229
368
  if (!parentMain || !parentModalDialog) return
@@ -238,7 +377,6 @@ const onRemoveScreenshot = (): void => {
238
377
  feedbackImgWrap.value.style.width = 0 + 'px'
239
378
  feedbackImgWrap.value.style.height = 0 + 'px'
240
379
  const value = {
241
- hasTakeScreenshot: false,
242
380
  width: memoryParentModalDialog.value,
243
381
  }
244
382
  emits('screen-shot', value)
@@ -256,6 +394,50 @@ const clearAll = (): void => {
256
394
  context.putImageData(drawingArray[indexArray.value], 0, 0)
257
395
  }
258
396
  }
397
+
398
+ const onUseRedMarker = (): void => {
399
+ drawColor = '#f76945'
400
+ drawWidth = '5'
401
+ }
402
+ const onUseGrayEraser = (): void => {
403
+ drawColor = 'lightgray'
404
+ drawWidth = '14'
405
+ }
406
+
407
+ const onUndoLast = (): void => {
408
+ drawColor = ''
409
+ drawWidth = ''
410
+ const context = feedbackImg.value.getContext('2d')
411
+ if (indexArray.value > 0) {
412
+ indexArray.value -= 1
413
+ drawingArray.pop()
414
+ context.putImageData(drawingArray[indexArray.value], 0, 0)
415
+ }
416
+ }
417
+
418
+ onMounted(() => {
419
+ feedbackImg.value.addEventListener('touchstart', start, false)
420
+ feedbackImg.value.addEventListener('touchmove', draw, false)
421
+ feedbackImg.value.addEventListener('mousedown', start, false)
422
+ feedbackImg.value.addEventListener('mousemove', draw, false)
423
+ feedbackImg.value.addEventListener('touchend', stop, false)
424
+ feedbackImg.value.addEventListener('mouseup', stop, false)
425
+ feedbackImg.value.addEventListener('mouseout', stop, false)
426
+ })
427
+
428
+ onBeforeUnmount(() => {
429
+ onRemoveScreenshot()
430
+ feedbackImg.value.removeEventListener('touchstart', start, false)
431
+ feedbackImg.value.removeEventListener('touchmove', draw, false)
432
+ feedbackImg.value.removeEventListener('mousedown', start, false)
433
+ feedbackImg.value.removeEventListener('mousemove', draw, false)
434
+ feedbackImg.value.removeEventListener('touchend', stop, false)
435
+ feedbackImg.value.removeEventListener('mouseup', stop, false)
436
+ feedbackImg.value.removeEventListener('mouseout', stop, false)
437
+ })
438
+ const onAnnotateImage = (): void => {
439
+ optionsModel.value.isAnnotateImage = true
440
+ }
259
441
  </script>
260
442
 
261
443
  <style lang="scss" scoped>
@@ -277,6 +459,27 @@ const clearAll = (): void => {
277
459
  }
278
460
  }
279
461
  }
462
+ .drawer-btn-container {
463
+ margin-bottom: 12px;
464
+ & > div {
465
+ display: flex;
466
+ align-items: center;
467
+ justify-content: space-between;
468
+ gap: 15px;
469
+ }
470
+ display: flex;
471
+ align-items: center;
472
+ justify-content: space-between;
473
+
474
+ .ui-btn {
475
+ width: initial;
476
+
477
+ &.clear-all {
478
+ color: #ea3223;
479
+ }
480
+ }
481
+ }
482
+
280
483
  &__alert {
281
484
  margin-bottom: 16px;
282
485
  }
@@ -285,6 +488,10 @@ const clearAll = (): void => {
285
488
  width: 500px;
286
489
  height: 280px;
287
490
  position: relative;
491
+ &.annotate {
492
+ width: 100%;
493
+ height: 460px;
494
+ }
288
495
  &.disabled {
289
496
  display: none;
290
497
  }
@@ -325,7 +532,7 @@ const clearAll = (): void => {
325
532
  }
326
533
  }
327
534
 
328
- &:hover &__backdrop {
535
+ &:hover:not(&.annotate) &__backdrop {
329
536
  display: flex;
330
537
  align-items: center;
331
538
  justify-content: center;
@@ -0,0 +1,4 @@
1
+ export interface UI_I_FeedbackCanvasOptions {
2
+ isAnnotateImage: boolean
3
+ hasTakeScreenshot: boolean
4
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "bfg-common",
3
3
  "private": false,
4
- "version": "1.4.390",
4
+ "version": "1.4.393",
5
5
  "scripts": {
6
6
  "build": "nuxt build",
7
7
  "dev": "nuxt dev --port=3002",
@@ -35,7 +35,7 @@
35
35
  "@vueuse/components": "^10.1.2",
36
36
  "date-fns": "^2.29.3",
37
37
  "bfg-nuxt-3-graph": "1.0.15",
38
- "bfg-uikit": "1.0.192",
38
+ "bfg-uikit": "1.0.195",
39
39
  "html2canvas": "^1.4.1",
40
40
  "prettier-eslint": "^15.0.1"
41
41
  }