From f41fff7ab3e4ad90cd620c5e2f4ad822a87c4c82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=CC=8Cimon=20Macek?= Date: Mon, 2 Sep 2024 19:16:15 +0200 Subject: [PATCH 01/10] core component html --- .../__tests__/TableNotifications.cy.js | 39 ++++++ src/components/profile/TableNotifications.vue | 127 ++++++++++++++++++ src/components/types/Notifications.ts | 15 +++ test/cypress/fixtures/tableNotifications.json | 77 +++++++++++ 4 files changed, 258 insertions(+) create mode 100644 src/components/__tests__/TableNotifications.cy.js create mode 100644 src/components/profile/TableNotifications.vue create mode 100644 src/components/types/Notifications.ts create mode 100644 test/cypress/fixtures/tableNotifications.json diff --git a/src/components/__tests__/TableNotifications.cy.js b/src/components/__tests__/TableNotifications.cy.js new file mode 100644 index 000000000..975c54603 --- /dev/null +++ b/src/components/__tests__/TableNotifications.cy.js @@ -0,0 +1,39 @@ +import TableNotifications from 'components/profile/TableNotifications.vue'; +import { i18n } from '../../boot/i18n'; + +// selectors +const tableNotifications = 'table-notifications'; + +describe('', () => { + it('has translation for all strings', () => { + cy.testLanguageStringsInContext([], 'index.component', i18n); + }); + + context('desktop', () => { + beforeEach(() => { + cy.mount(TableNotifications, { + props: {}, + }); + cy.viewport('macbook-16'); + }); + + coreTests(); + }); + + context('mobile', () => { + beforeEach(() => { + cy.mount(TableNotifications, { + props: {}, + }); + cy.viewport('iphone-6'); + }); + + coreTests(); + }); +}); + +function coreTests() { + it('renders component', () => { + cy.dataCy(tableNotifications).should('be.visible'); + }); +} diff --git a/src/components/profile/TableNotifications.vue b/src/components/profile/TableNotifications.vue new file mode 100644 index 000000000..9aec275b9 --- /dev/null +++ b/src/components/profile/TableNotifications.vue @@ -0,0 +1,127 @@ + + + diff --git a/src/components/types/Notifications.ts b/src/components/types/Notifications.ts new file mode 100644 index 000000000..21bbd8ba5 --- /dev/null +++ b/src/components/types/Notifications.ts @@ -0,0 +1,15 @@ +export interface Notification { + mark_as_read: string; + mark_as_unread: string; + id: number; + level: string; + unread: boolean; + deleted: boolean; + verb: string; + description: string | null; + timestamp: string; + data: { + url: string; + icon: string; + }; +} diff --git a/test/cypress/fixtures/tableNotifications.json b/test/cypress/fixtures/tableNotifications.json new file mode 100644 index 000000000..de6ba3652 --- /dev/null +++ b/test/cypress/fixtures/tableNotifications.json @@ -0,0 +1,77 @@ +[ + { + "mark_as_read": "Mark as read", + "mark_as_unread": "Mark as unread", + "id": 1, + "level": "info", + "unread": true, + "deleted": false, + "verb": "New message", + "description": "You have a new message from your coordinator.", + "timestamp": "2023-05-15T10:30:00Z", + "data": { + "url": "/messages/1", + "icon": "mail" + } + }, + { + "mark_as_read": "Mark as read", + "mark_as_unread": "Mark as unread", + "id": 2, + "level": "success", + "unread": false, + "deleted": false, + "verb": "Challenge completed", + "description": "Congratulations! You've completed the weekly challenge.", + "timestamp": "2023-05-14T18:45:00Z", + "data": { + "url": "/challenges/weekly", + "icon": "trophy" + } + }, + { + "mark_as_read": "Mark as read", + "mark_as_unread": "Mark as unread", + "id": 3, + "level": "warning", + "unread": true, + "deleted": false, + "verb": "Profile update required", + "description": "Please update your profile information.", + "timestamp": "2023-05-13T09:15:00Z", + "data": { + "url": "/profile", + "icon": "person" + } + }, + { + "mark_as_read": "Mark as read", + "mark_as_unread": "Mark as unread", + "id": 4, + "level": "error", + "unread": true, + "deleted": false, + "verb": "Payment failed", + "description": "Your recent payment for the challenge registration has failed.", + "timestamp": "2023-05-12T14:20:00Z", + "data": { + "url": "/payments", + "icon": "warning" + } + }, + { + "mark_as_read": "Mark as read", + "mark_as_unread": "Mark as unread", + "id": 5, + "level": "info", + "unread": false, + "deleted": false, + "verb": "New team member", + "description": "A new member has joined your team.", + "timestamp": "2023-05-11T11:00:00Z", + "data": { + "url": "/team", + "icon": "group_add" + } + } +] From f0396650e98348adf923afb8005f1d0957c862ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=CC=8Cimon=20Macek?= Date: Tue, 3 Sep 2024 15:34:45 +0200 Subject: [PATCH 02/10] labels --- src/i18n/cs.toml | 8 ++++++++ src/i18n/en.toml | 8 ++++++++ src/i18n/sk.toml | 8 ++++++++ 3 files changed, 24 insertions(+) diff --git a/src/i18n/cs.toml b/src/i18n/cs.toml index bb5b9c9f4..cb1a5ef2d 100755 --- a/src/i18n/cs.toml +++ b/src/i18n/cs.toml @@ -436,6 +436,14 @@ description = "Stáhněte si appku a zapisujte jízdy odkudkoliv." voucherApplySuccess = "Voucher byl úspěšně uplatněn" voucherApplyError = "Neplatný voucher" +[notifications] +labelAction = "Akce" +labelDate = "Datum" +labelRead = "Přečteno" +labelState = "Stav" +labelTitle = "Notifikace" +labelUnread = "Nepřečteno" + [offer] titleOfferValidation = "Pro využití se stačí na místě prokázat:" labelOfferValidationTshirt = "Trikem nebo nákrčníkem" diff --git a/src/i18n/en.toml b/src/i18n/en.toml index aea757667..9f2374fa4 100755 --- a/src/i18n/en.toml +++ b/src/i18n/en.toml @@ -433,6 +433,14 @@ description = "Download the app and log rides from anywhere." voucherApplySuccess = "Voucher successfully redeemed" voucherApplyError = "Invalid voucher" +[notifications] +labelAction = "Action" +labelDate = "Date" +labelRead = "Read" +labelState = "State" +labelTitle = "Notification" +labelUnread = "Unread" + [offer] titleOfferValidation = "To use it, just show proof of identity on the spot:" labelOfferValidationTshirt = "T-shirt or neck warmer" diff --git a/src/i18n/sk.toml b/src/i18n/sk.toml index 3501f4dba..9e28ab5d3 100755 --- a/src/i18n/sk.toml +++ b/src/i18n/sk.toml @@ -433,6 +433,14 @@ description = "Stiahnite si aplikáciu a prihlasujte jazdy odkiaľkoľvek." voucherApplySuccess = "Voucher bol úspešne uplatnený" voucherApplyError = "Neplatný voucher" +[notifications] +labelAction = "Akcia" +labelDate = "Dátum" +labelRead = "Prečité" +labelState = "Stav" +labelTitle = "Oznámenie" +labelUnread = "Neprečité" + [offer] titleOfferValidation = "Chcete-li ji použít, stačí se na místě prokázat dokladem totožnosti:" labelOfferValidationTshirt = "Tričko nebo nákrčník" From 1f92e33c3a9502e56cef36d21dbd9a9f79d06f4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=CC=8Cimon=20Macek?= Date: Tue, 3 Sep 2024 15:58:19 +0200 Subject: [PATCH 03/10] update tests --- .../__tests__/TableNotifications.cy.js | 80 +++++++++++++++++-- src/components/profile/TableNotifications.vue | 34 ++++---- 2 files changed, 91 insertions(+), 23 deletions(-) diff --git a/src/components/__tests__/TableNotifications.cy.js b/src/components/__tests__/TableNotifications.cy.js index 975c54603..69ba1fdae 100644 --- a/src/components/__tests__/TableNotifications.cy.js +++ b/src/components/__tests__/TableNotifications.cy.js @@ -1,12 +1,37 @@ +import { date } from 'quasar'; import TableNotifications from 'components/profile/TableNotifications.vue'; import { i18n } from '../../boot/i18n'; // selectors -const tableNotifications = 'table-notifications'; +const dataSelectorNotificationTitle = '[data-cy="notification-title"]'; +const dataSelectorNotificationTimestamp = '[data-cy="notification-timestamp"]'; +const dataSelectorNotificationUnread = '[data-cy="notification-unread"]'; +const dataSelectorNotificationAction = '[data-cy="notification-action"]'; +const selectorTableNotifications = 'table-notifications'; +const selectorNotificationRow = 'notification-row'; describe('', () => { it('has translation for all strings', () => { - cy.testLanguageStringsInContext([], 'index.component', i18n); + cy.testLanguageStringsInContext( + [ + 'labelAction', + 'labelDate', + 'labelRead', + 'labelState', + 'labelTitle', + 'labelUnread', + ], + 'notifications', + i18n, + ); + }); + + let notifications; + + before(() => { + cy.fixture('tableNotifications').then((data) => { + notifications = data; + }); }); context('desktop', () => { @@ -30,10 +55,49 @@ describe('', () => { coreTests(); }); -}); -function coreTests() { - it('renders component', () => { - cy.dataCy(tableNotifications).should('be.visible'); - }); -} + function coreTests() { + it('renders component', () => { + cy.dataCy(selectorTableNotifications).should('be.visible'); + }); + + it('renders notifications', () => { + cy.dataCy(selectorNotificationRow) + .should('be.visible') + .should('have.length', 5); + cy.dataCy(selectorTableNotifications) // scroll to the right + .find('.scroll') + .scrollTo('right', { + ensureScrollable: false, + }); + cy.dataCy(selectorNotificationRow).each((row, index) => { + const notification = notifications[index]; + cy.wrap(row) + .find(dataSelectorNotificationTitle) + .should('be.visible') + .should('contain', notification.verb); + cy.wrap(row) + .find(dataSelectorNotificationTimestamp) + .should('be.visible') + .should( + 'contain', + date.formatDate( + new Date(String(notification.timestamp)), + 'D. MMM. YYYY', + ), + ); + cy.wrap(row) + .find(dataSelectorNotificationUnread) + .should('be.visible') + .should( + 'contain', + notification.unread + ? i18n.global.t('notifications.labelUnread') + : i18n.global.t('notifications.labelRead'), + ); + + cy.wrap(row).find(dataSelectorNotificationAction).should('be.visible'); + }); + }); + } +}); diff --git a/src/components/profile/TableNotifications.vue b/src/components/profile/TableNotifications.vue index 9aec275b9..fa1aaaf3b 100644 --- a/src/components/profile/TableNotifications.vue +++ b/src/components/profile/TableNotifications.vue @@ -17,7 +17,7 @@ // libraries import { date } from 'quasar'; -import { defineComponent } from 'vue'; +import { defineComponent, reactive } from 'vue'; // composables import { i18n } from '../../boot/i18n'; @@ -65,11 +65,16 @@ export default defineComponent({ }, ]; - const rows: Notification[] = tableNotificationsFixture; + const rows = reactive(tableNotificationsFixture); + + const markAsRead = (row: Notification) => { + row.unread = false; + }; return { columns, rows, + markAsRead, }; }, }); @@ -80,27 +85,24 @@ export default defineComponent({
- +