From 736a6a3d78b8a599e8b5cfef839e3b3ae8f1b61a Mon Sep 17 00:00:00 2001 From: Greg Slepak Date: Mon, 25 Nov 2024 08:39:06 -0800 Subject: [PATCH 1/4] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 98c7dc1680..9999e883a4 100644 --- a/README.md +++ b/README.md @@ -122,6 +122,8 @@ npm run cy:open npx cypress run -c 'baseUrl=http://localhost:8000' --spec "test/cypress/integration/group-chat.spec.js" ``` +This project is tested with BrowserStack. + #### Using Docker for extra security You can run commands in a Docker container by using `npm run docker -- ` instead. From 05835cbc82dd789b9868e06590351a9334397486 Mon Sep 17 00:00:00 2001 From: Sebin Song Date: Tue, 26 Nov 2024 07:04:41 +1300 Subject: [PATCH 2/4] #2406 - payment table UI issue (#2410) * add custom desktop bp for payment-table * make sure todo-table looks good --- frontend/assets/style/_mixins.scss | 7 +++ .../payments/PaymentRowReceived.vue | 2 +- .../containers/payments/PaymentRowSent.vue | 2 +- .../containers/payments/PaymentsList.vue | 55 +++++++++++++++---- .../payments/payment-row/PaymentRow.vue | 8 ++- frontend/views/pages/Payments.vue | 25 +++------ 6 files changed, 68 insertions(+), 31 deletions(-) diff --git a/frontend/assets/style/_mixins.scss b/frontend/assets/style/_mixins.scss index 5927b5fff3..8be7245cc9 100644 --- a/frontend/assets/style/_mixins.scss +++ b/frontend/assets/style/_mixins.scss @@ -48,6 +48,13 @@ } } +$payment-table-desktop-bp: 1290px; +@mixin payment-table-desktop { + @media screen and (min-width: $payment-table-desktop-bp) { + @content; + } +} + %unselectable { -webkit-touch-callout: none; -webkit-user-select: none; diff --git a/frontend/views/containers/payments/PaymentRowReceived.vue b/frontend/views/containers/payments/PaymentRowReceived.vue index c3103e815b..4bd578bb53 100644 --- a/frontend/views/containers/payments/PaymentRowReceived.vue +++ b/frontend/views/containers/payments/PaymentRowReceived.vue @@ -129,7 +129,7 @@ export default ({ .c-relative-to { display: none; - @include desktop { + @include payment-table-desktop { display: block; } } diff --git a/frontend/views/containers/payments/PaymentRowSent.vue b/frontend/views/containers/payments/PaymentRowSent.vue index 55d1166d57..52ed80ab7e 100644 --- a/frontend/views/containers/payments/PaymentRowSent.vue +++ b/frontend/views/containers/payments/PaymentRowSent.vue @@ -117,7 +117,7 @@ export default ({ .c-relative-to { display: none; - @include desktop { + @include payment-table-desktop { display: block; } } diff --git a/frontend/views/containers/payments/PaymentsList.vue b/frontend/views/containers/payments/PaymentsList.vue index e1facf0adf..a61e402f12 100644 --- a/frontend/views/containers/payments/PaymentsList.vue +++ b/frontend/views/containers/payments/PaymentsList.vue @@ -150,33 +150,51 @@ export default ({ text-align: right; } - @include desktop { + @include payment-table-desktop { min-width: 4.5rem; } } th.c-th-method { - @include desktop { + @include payment-table-desktop { min-width: 7.25rem; } } th.c-th-date { - @include desktop { + @include payment-table-desktop { min-width: 6.25rem; } } th.c-th-relative-to { - @include desktop { + @include payment-table-desktop { min-width: 5.25rem; } } ::v-deep td.c-td-user { - @include desktop { + @include tablet { padding-right: 0.5rem; } + + @include desktop { + max-width: 12rem; + min-width: 10rem; + overflow: hidden; + + .c-user { + max-width: inherit; + + .c-twrapper { + width: 100%; + } + } + } + + @include from (1360px) { + max-width: 16rem; + } } &.c-is-todo { @@ -193,19 +211,31 @@ export default ({ width: 40%; @include tablet { - width: 27%; + width: 35%; } } th.c-th-method { width: 20%; + + @include tablet { + padding-right: 0.5rem; + min-width: 8rem; + } } th.c-th-amount { width: 55%; @include tablet { - width: 24%; + width: 16%; + } + } + + th.c-th-date { + @include desktop { + padding-right: 1.5rem; + min-width: 4.25rem; } } } @@ -234,9 +264,10 @@ export default ({ th.c-th-method { @include tablet { width: 24%; + padding-right: 0.5rem; } - @include desktop { + @include payment-table-desktop { width: 19%; } } @@ -244,13 +275,17 @@ export default ({ th.c-th-date { width: 18%; padding-right: 0.5rem; + + @include desktop { + width: 22%; + } } th.c-th-relative-to { display: none; padding-right: 0; - @include desktop { + @include payment-table-desktop { display: table-cell; width: 14%; } @@ -259,7 +294,7 @@ export default ({ th.c-th-action { display: none; - @include desktop { + @include payment-table-desktop { display: table-cell; width: 5%; } diff --git a/frontend/views/containers/payments/payment-row/PaymentRow.vue b/frontend/views/containers/payments/payment-row/PaymentRow.vue index 7282a51696..769dfa5433 100644 --- a/frontend/views/containers/payments/payment-row/PaymentRow.vue +++ b/frontend/views/containers/payments/payment-row/PaymentRow.vue @@ -27,7 +27,7 @@ td(v-if='$slots["cellRelativeTo"]') slot(name='cellRelativeTo') - td + td.c-td-actions .cpr-actions slot(name='cellActions') @@ -111,4 +111,10 @@ export default ({ margin-left: 0; } } + +td.c-td-actions { + @include desktop { + padding-right: 1.5rem; + } +} diff --git a/frontend/views/pages/Payments.vue b/frontend/views/pages/Payments.vue index a97c2f7051..b991560063 100644 --- a/frontend/views/pages/Payments.vue +++ b/frontend/views/pages/Payments.vue @@ -90,14 +90,13 @@ page( .tab-section .c-container(v-if='paymentsFiltered.length') - .c-payments-table-container - payments-list( - ref='paymentList' - :titles='tableTitles' - :paymentsList='paginateList(paymentsFiltered)' - :paymentsType='ephemeral.activeTab' - :selectedTodoItems.sync='ephemeral.selectedTodoItems' - ) + payments-list( + ref='paymentList' + :titles='tableTitles' + :paymentsList='paginateList(paymentsFiltered)' + :paymentsType='ephemeral.activeTab' + :selectedTodoItems.sync='ephemeral.selectedTodoItems' + ) .c-footer .c-payment-record(v-if='ephemeral.activeTab === "PaymentRowTodo"') @@ -658,16 +657,6 @@ export default ({ } } -.c-payments-table-container { - position: relative; - - @include desktop { - width: 100%; - overflow-x: auto; - overflow-y: hidden; - } -} - .c-container-empty { max-width: 25rem; margin: 0 auto; From fac9a1b067cd5097ce2b15c85423972d0fb343dc Mon Sep 17 00:00:00 2001 From: Sebin Song Date: Wed, 27 Nov 2024 09:27:17 +1300 Subject: [PATCH 3/4] #2412 `` key issue on mobile (#2413) * fix the issue * fix linter err * uncomment SW err handling * add comment * move mediaIsPhone to data() --- .../views/containers/chatroom/SendArea.vue | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/frontend/views/containers/chatroom/SendArea.vue b/frontend/views/containers/chatroom/SendArea.vue index e73e21ea07..8885d02d72 100644 --- a/frontend/views/containers/chatroom/SendArea.vue +++ b/frontend/views/containers/chatroom/SendArea.vue @@ -65,7 +65,7 @@ :style='textareaStyles' :maxlength='config.messageMaxChar' @blur='textAreaBlur' - @keydown.enter.exact.prevent='handleKeyDownEnter' + @keydown.enter.exact='handleKeyDownEnter' @keydown.tab.exact='handleKeyDownTab' @keydown.ctrl='isNextLine' @keydown='handleKeydown' @@ -359,7 +359,8 @@ export default ({ messageMaxChar: CHATROOM_MAX_MESSAGE_LEN }, typingUserTimeoutIds: {}, - throttledEmitUserTypingEvent: throttle(this.emitUserTypingEvent, 500) + throttledEmitUserTypingEvent: throttle(this.emitUserTypingEvent, 500), + mediaIsPhone: null } }, watch: { @@ -376,9 +377,9 @@ export default ({ }, created () { // TODO #492 create a global Vue Responsive just for media queries. - const mediaIsPhone = window.matchMedia('(hover: none) and (pointer: coarse)') - this.ephemeral.isPhone = mediaIsPhone.matches - mediaIsPhone.onchange = (e) => { this.ephemeral.isPhone = e.matches } + this.mediaIsPhone = window.matchMedia('(hover: none) and (pointer: coarse)') + this.ephemeral.isPhone = this.mediaIsPhone.matches + this.mediaIsPhone.onchange = (e) => { this.ephemeral.isPhone = e.matches } }, mounted () { this.$refs.textarea.value = this.defaultText || '' @@ -397,6 +398,7 @@ export default ({ sbp('okTurtles.events/off', CHATROOM_USER_TYPING, this.onUserTyping) sbp('okTurtles.events/off', CHATROOM_USER_STOP_TYPING, this.onUserStopTyping) + this.mediaIsPhone.onchange = null // change handler needs to be destoryed to prevent memory leak. this.ephemeral.staleObjectURLs.forEach(url => { URL.revokeObjectURL(url) }) @@ -531,12 +533,16 @@ export default ({ this.$refs.textarea.focus() this.addSelectedMention(index) }, - handleKeyDownEnter () { + handleKeyDownEnter (e) { + const isNotPhone = !this.ephemeral.isPhone + if (this.ephemeral.mention.options.length) { this.addSelectedMention(this.ephemeral.mention.index) - } else { + } else if (isNotPhone) { this.sendMessage() } + + isNotPhone && e.preventDefault() }, handleKeyDownTab (e) { if (this.ephemeral.mention.options.length) { From 4464feab187308af2cfeefa6a73ed8f5161f99a3 Mon Sep 17 00:00:00 2001 From: Sebin Song Date: Thu, 28 Nov 2024 08:02:53 +1300 Subject: [PATCH 4/4] #2391 - Multiple images in the viewer (#2419) * extract all imagesgrunt dev * send multiple image data to ImageViewerModal.vue * render multiple images back to back in a container * add prev/next btn to the modal * implement keydown event for iamge navigation * add loader animation to PreviewImageArea.vue * add isTouch / fix isLoaded / update nav buttons * fix the mobile issue * fix the bug where the image abruptly changes the dimension * revert the SW err handler * update for Greg feedbacks --- .../file-attachment/ChatAttachmentPreview.vue | 41 +++-- .../image-viewer/ImageViewerModal.vue | 149 ++++++++++++++---- .../image-viewer/PreviewImageArea.vue | 48 +++++- frontend/views/utils/pointerEventsMixins.js | 14 +- 4 files changed, 195 insertions(+), 57 deletions(-) diff --git a/frontend/views/containers/chatroom/file-attachment/ChatAttachmentPreview.vue b/frontend/views/containers/chatroom/file-attachment/ChatAttachmentPreview.vue index 0edef12a61..bfbc987357 100644 --- a/frontend/views/containers/chatroom/file-attachment/ChatAttachmentPreview.vue +++ b/frontend/views/containers/chatroom/file-attachment/ChatAttachmentPreview.vue @@ -22,7 +22,7 @@ v-if='objectURLList[entryIndex]' :src='objectURLList[entryIndex]' :alt='entry.name' - @click='openImageViewer(objectURLList[entryIndex], entry)' + @click='openImageViewer(objectURLList[entryIndex])' ) .loading-box(v-else :style='loadingBoxStyles[entryIndex]') @@ -60,7 +60,7 @@ v-for='(entry, entryIndex) in attachmentList' :key='entryIndex' :class='"is-" + fileType(entry)' - @click='openImageViewer(entry.url, entry)' + @click='openImageViewer(entry.url)' ) img.c-preview-img( v-if='fileType(entry) === "image" && entry.url' @@ -94,6 +94,7 @@ import { MESSAGE_VARIANTS } from '@model/contracts/shared/constants.js' import { getFileExtension, getFileType } from '@view-utils/filters.js' import { Secret } from '~/shared/domains/chelonia/Secret.js' import { OPEN_MODAL } from '@utils/events.js' +import { randomHexString } from '@model/contracts/shared/giLodash.js' export default { name: 'ChatAttachmentPreview', @@ -212,21 +213,29 @@ export default { height: `${heightInPixel}px` } }, - openImageViewer (objectURL, data) { - if (objectURL) { - sbp( - 'okTurtles.events/emit', OPEN_MODAL, 'ImageViewerModal', - null, - { - metaData: { - name: data.name, - ownerID: this.ownerID, - imgUrl: objectURL, - createdAt: this.createdAt || new Date() - } + openImageViewer (objectURL) { + if (!objectURL) { return } + + const allImageAttachments = this.attachmentList.filter(entry => this.fileType(entry) === 'image') + .map((entry, index) => { + return { + name: entry.name, + ownerID: this.ownerID, + imgUrl: entry.url || this.objectURLList[index] || '', + createdAt: this.createdAt || new Date(), + id: randomHexString(12) } - ) - } + }) + const initialIndex = allImageAttachments.findIndex(attachment => attachment.imgUrl === objectURL) + + sbp( + 'okTurtles.events/emit', OPEN_MODAL, 'ImageViewerModal', + null, + { + images: allImageAttachments, + initialIndex: initialIndex === -1 ? 0 : initialIndex + } + ) } }, watch: { diff --git a/frontend/views/containers/chatroom/image-viewer/ImageViewerModal.vue b/frontend/views/containers/chatroom/image-viewer/ImageViewerModal.vue index 4dbe4624cf..461e7a83f4 100644 --- a/frontend/views/containers/chatroom/image-viewer/ImageViewerModal.vue +++ b/frontend/views/containers/chatroom/image-viewer/ImageViewerModal.vue @@ -2,24 +2,43 @@ .c-image-viewer-modal(@wheel.prevent.stop='') .c-image-viewer-content .c-image-blurry-background(:style='blurryBgStyles') - preview-image-area(:img-src='metaData.imgUrl' :name='metaData.name') + preview-image-area( + v-if='currentImage' + :key='currentImage.id' + :img-src='currentImage.imgUrl' + :name='currentImage.name' + ) header.c-modal-header avatar-user.c-avatar( - v-if='metaData.ownerID' - :contractID='metaData.ownerID' + v-if='currentImage.ownerID' + :contractID='currentImage.ownerID' size='sm' ) .c-img-data .c-name.has-ellipsis {{ displayName }} - .c-filename.has-ellipsis {{ metaData.name }} + .c-filename.has-ellipsis {{ currentImage.name }} button.is-icon-small.c-close-btn( type='button' @click.stop='close' ) i.icon-times + + button.is-icon.c-image-nav-btn.is-prev( + v-if='showPrevButton' + type='button' + @click='selectPrevImage' + ) + i.icon-chevron-left + + button.is-icon.c-image-nav-btn.is-next( + v-if='showNextButton' + type='button' + @click='selectNextImage' + ) + i.icon-chevron-right