diff --git a/admin/src/components/ContributionMessages/ContributionMessagesFormular.spec.js b/admin/src/components/ContributionMessages/ContributionMessagesFormular.spec.js new file mode 100644 index 000000000..62fcab505 --- /dev/null +++ b/admin/src/components/ContributionMessages/ContributionMessagesFormular.spec.js @@ -0,0 +1,111 @@ +import { mount } from '@vue/test-utils' +import ContributionMessagesFormular from './ContributionMessagesFormular.vue' +import { toastErrorSpy, toastSuccessSpy } from '../../../test/testSetup' + +const localVue = global.localVue + +const apolloMutateMock = jest.fn().mockResolvedValue() + +describe('ContributionMessagesFormular', () => { + let wrapper + + const propsData = { + contributionId: 42, + } + + const mocks = { + $t: jest.fn((t) => t), + $apollo: { + mutate: apolloMutateMock, + }, + $i18n: { + locale: 'en', + }, + } + + const Wrapper = () => { + return mount(ContributionMessagesFormular, { + localVue, + mocks, + propsData, + }) + } + + describe('mount', () => { + beforeEach(() => { + wrapper = Wrapper() + }) + + it('has a DIV .contribution-messages-formular', () => { + expect(wrapper.find('div.contribution-messages-formular').exists()).toBe(true) + }) + + describe('on trigger reset', () => { + beforeEach(async () => { + wrapper.setData({ + form: { + text: 'text form message', + }, + }) + await wrapper.find('form').trigger('reset') + }) + + it('form has empty text', () => { + expect(wrapper.vm.form).toEqual({ + text: '', + }) + }) + }) + + describe('on trigger submit', () => { + beforeEach(async () => { + wrapper.setData({ + form: { + text: 'text form message', + }, + }) + await wrapper.find('form').trigger('submit') + }) + + it('emitted "get-list-contribution-messages" with data', async () => { + expect(wrapper.emitted('get-list-contribution-messages')).toEqual( + expect.arrayContaining([expect.arrayContaining([42])]), + ) + }) + + it('emitted "update-state" with data', async () => { + expect(wrapper.emitted('update-state')).toEqual( + expect.arrayContaining([expect.arrayContaining([42])]), + ) + }) + }) + + describe('send contribution message with error', () => { + beforeEach(async () => { + apolloMutateMock.mockRejectedValue({ message: 'OUCH!' }) + wrapper = Wrapper() + await wrapper.find('form').trigger('submit') + }) + + it('toasts an error message', () => { + expect(toastErrorSpy).toBeCalledWith('OUCH!') + }) + }) + + describe('send contribution message with success', () => { + beforeEach(async () => { + wrapper.setData({ + form: { + text: 'text form message', + }, + }) + wrapper = Wrapper() + await wrapper.find('form').trigger('submit') + }) + + it('toasts an success message', () => { + expect(toastSuccessSpy).toBeCalledWith('message.request') + }) + }) + }) +}) diff --git a/admin/src/components/ContributionMessages/ContributionMessagesFormular.vue b/admin/src/components/ContributionMessages/ContributionMessagesFormular.vue new file mode 100644 index 000000000..15fc4f78d --- /dev/null +++ b/admin/src/components/ContributionMessages/ContributionMessagesFormular.vue @@ -0,0 +1,67 @@ + + diff --git a/admin/src/components/ContributionMessages/ContributionMessagesList.spec.js b/admin/src/components/ContributionMessages/ContributionMessagesList.spec.js new file mode 100644 index 000000000..0bca08b2a --- /dev/null +++ b/admin/src/components/ContributionMessages/ContributionMessagesList.spec.js @@ -0,0 +1,56 @@ +import { mount } from '@vue/test-utils' +import ContributionMessagesList from './ContributionMessagesList.vue' + +const localVue = global.localVue + +const apolloQueryMock = jest.fn().mockResolvedValue() + +describe('ContributionMessagesList', () => { + let wrapper + + const propsData = { + contributionId: 42, + } + + const mocks = { + $t: jest.fn((t) => t), + $i18n: { + locale: 'en', + }, + $apollo: { + query: apolloQueryMock, + }, + } + + const Wrapper = () => { + return mount(ContributionMessagesList, { + localVue, + mocks, + propsData, + }) + } + + describe('mount', () => { + beforeEach(() => { + wrapper = Wrapper() + }) + + it('sends query to Apollo when created', () => { + expect(apolloQueryMock).toBeCalledWith( + expect.objectContaining({ + variables: { + contributionId: propsData.contributionId, + }, + }), + ) + }) + + it('has a DIV .contribution-messages-list', () => { + expect(wrapper.find('div.contribution-messages-list').exists()).toBe(true) + }) + + it('has a Component ContributionMessagesFormular', () => { + expect(wrapper.findComponent({ name: 'ContributionMessagesFormular' }).exists()).toBe(true) + }) + }) +}) diff --git a/admin/src/components/ContributionMessages/ContributionMessagesList.vue b/admin/src/components/ContributionMessages/ContributionMessagesList.vue new file mode 100644 index 000000000..8f5a3e119 --- /dev/null +++ b/admin/src/components/ContributionMessages/ContributionMessagesList.vue @@ -0,0 +1,69 @@ + + + diff --git a/admin/src/components/ContributionMessages/slots/ContributionMessagesListItem.spec.js b/admin/src/components/ContributionMessages/slots/ContributionMessagesListItem.spec.js new file mode 100644 index 000000000..7cca315d7 --- /dev/null +++ b/admin/src/components/ContributionMessages/slots/ContributionMessagesListItem.spec.js @@ -0,0 +1,58 @@ +import { mount } from '@vue/test-utils' +import ContributionMessagesListItem from './ContributionMessagesListItem.vue' + +const localVue = global.localVue + +describe('ContributionMessagesListItem', () => { + let wrapper + + const mocks = { + $t: jest.fn((t) => t), + $d: jest.fn((d) => d), + $store: { + state: { + moderator: { + id: 107, + }, + }, + }, + } + + const propsData = { + contributionId: 42, + state: 'PENDING0', + message: { + id: 111, + message: 'asd asda sda sda', + createdAt: '2022-08-29T12:23:27.000Z', + updatedAt: null, + type: 'DIALOG', + userFirstName: 'Peter', + userLastName: 'Lustig', + userId: 107, + __typename: 'ContributionMessage', + }, + } + + const Wrapper = () => { + return mount(ContributionMessagesListItem, { + localVue, + mocks, + propsData, + }) + } + + describe('mount', () => { + beforeEach(() => { + wrapper = Wrapper() + }) + + it('has a DIV .contribution-messages-list-item', () => { + expect(wrapper.find('div.contribution-messages-list-item').exists()).toBe(true) + }) + + it('props.message.default', () => { + expect(wrapper.vm.$options.props.message.default.call()).toEqual({}) + }) + }) +}) diff --git a/admin/src/components/ContributionMessages/slots/ContributionMessagesListItem.vue b/admin/src/components/ContributionMessages/slots/ContributionMessagesListItem.vue new file mode 100644 index 000000000..7ee0134ac --- /dev/null +++ b/admin/src/components/ContributionMessages/slots/ContributionMessagesListItem.vue @@ -0,0 +1,32 @@ + + diff --git a/admin/src/components/ContributionMessages/slots/IsModerator.spec.js b/admin/src/components/ContributionMessages/slots/IsModerator.spec.js new file mode 100644 index 000000000..b1e09da94 --- /dev/null +++ b/admin/src/components/ContributionMessages/slots/IsModerator.spec.js @@ -0,0 +1,49 @@ +import { mount } from '@vue/test-utils' +import IsModerator from './IsModerator.vue' + +const localVue = global.localVue + +describe('IsModerator', () => { + let wrapper + + const mocks = { + $t: jest.fn((t) => t), + $d: jest.fn((d) => d), + } + + const propsData = { + message: { + id: 111, + message: 'asd asda sda sda', + createdAt: '2022-08-29T12:23:27.000Z', + updatedAt: null, + type: 'DIALOG', + userFirstName: 'Peter', + userLastName: 'Lustig', + userId: 107, + __typename: 'ContributionMessage', + }, + } + + const Wrapper = () => { + return mount(IsModerator, { + localVue, + mocks, + propsData, + }) + } + + describe('mount', () => { + beforeEach(() => { + wrapper = Wrapper() + }) + + it('has a DIV .slot-is-moderator', () => { + expect(wrapper.find('div.slot-is-moderator').exists()).toBe(true) + }) + + it('props.message.default', () => { + expect(wrapper.vm.$options.props.message.default.call()).toEqual({}) + }) + }) +}) diff --git a/admin/src/components/ContributionMessages/slots/IsModerator.vue b/admin/src/components/ContributionMessages/slots/IsModerator.vue new file mode 100644 index 000000000..37db5402e --- /dev/null +++ b/admin/src/components/ContributionMessages/slots/IsModerator.vue @@ -0,0 +1,37 @@ + + + diff --git a/admin/src/components/ContributionMessages/slots/IsNotModerator.spec.js b/admin/src/components/ContributionMessages/slots/IsNotModerator.spec.js new file mode 100644 index 000000000..24152ad1e --- /dev/null +++ b/admin/src/components/ContributionMessages/slots/IsNotModerator.spec.js @@ -0,0 +1,49 @@ +import { mount } from '@vue/test-utils' +import IsNotModerator from './IsNotModerator.vue' + +const localVue = global.localVue + +describe('IsNotModerator', () => { + let wrapper + + const mocks = { + $t: jest.fn((t) => t), + $d: jest.fn((d) => d), + } + + const propsData = { + message: { + id: 113, + message: 'asda sdad ad asdasd ', + createdAt: '2022-08-29T12:25:34.000Z', + updatedAt: null, + type: 'DIALOG', + userFirstName: 'Bibi', + userLastName: 'Bloxberg', + userId: 108, + __typename: 'ContributionMessage', + }, + } + + const Wrapper = () => { + return mount(IsNotModerator, { + localVue, + mocks, + propsData, + }) + } + + describe('mount', () => { + beforeEach(() => { + wrapper = Wrapper() + }) + + it('has a DIV .slot-is-not-moderator', () => { + expect(wrapper.find('div.slot-is-not-moderator').exists()).toBe(true) + }) + + it('props.message.default', () => { + expect(wrapper.vm.$options.props.message.default.call()).toEqual({}) + }) + }) +}) diff --git a/admin/src/components/ContributionMessages/slots/IsNotModerator.vue b/admin/src/components/ContributionMessages/slots/IsNotModerator.vue new file mode 100644 index 000000000..8828fe5b0 --- /dev/null +++ b/admin/src/components/ContributionMessages/slots/IsNotModerator.vue @@ -0,0 +1,36 @@ + + + diff --git a/admin/src/components/Tables/OpenCreationsTable.vue b/admin/src/components/Tables/OpenCreationsTable.vue index 3ebc81fba..86c5ecce6 100644 --- a/admin/src/components/Tables/OpenCreationsTable.vue +++ b/admin/src/components/Tables/OpenCreationsTable.vue @@ -21,6 +21,19 @@ > + + + + + diff --git a/frontend/src/graphql/mutations.js b/frontend/src/graphql/mutations.js index 959bdefc3..9846784d5 100644 --- a/frontend/src/graphql/mutations.js +++ b/frontend/src/graphql/mutations.js @@ -122,3 +122,17 @@ export const deleteContribution = gql` deleteContribution(id: $id) } ` + +export const createContributionMessage = gql` + mutation($contributionId: Float!, $message: String!) { + createContributionMessage(contributionId: $contributionId, message: $message) { + id + message + createdAt + updatedAt + type + userFirstName + userLastName + } + } +` diff --git a/frontend/src/graphql/queries.js b/frontend/src/graphql/queries.js index 88c312a3f..07b016d0a 100644 --- a/frontend/src/graphql/queries.js +++ b/frontend/src/graphql/queries.js @@ -257,3 +257,26 @@ export const searchAdminUsers = gql` } } ` + +export const listContributionMessages = gql` + query($contributionId: Float!, $pageSize: Int = 25, $currentPage: Int = 1, $order: Order = ASC) { + listContributionMessages( + contributionId: $contributionId + pageSize: $pageSize + currentPage: $currentPage + order: $order + ) { + count + messages { + id + message + createdAt + updatedAt + type + userFirstName + userLastName + userId + } + } + } +` diff --git a/frontend/src/locales/de.json b/frontend/src/locales/de.json index 7c9f37370..1525ed98c 100644 --- a/frontend/src/locales/de.json +++ b/frontend/src/locales/de.json @@ -22,6 +22,7 @@ "continue-to-registration": "Weiter zur Registrierung", "current-community": "Aktuelle Gemeinschaft", "members": "Mitglieder", + "moderator": "Moderator", "moderators": "Moderatoren", "myContributions": "Meine Beiträge zum Gemeinwohl", "openContributionLinks": "öffentliche Beitrags-Linkliste", @@ -34,10 +35,11 @@ "contribution": { "activity": "Tätigkeit", "alert": { + "answerQuestion": "Bitte beantworte die Nachfrage", "communityNoteList": "Hier findest du alle eingereichten und bestätigten Beiträge von allen Mitgliedern aus dieser Gemeinschaft.", "confirm": "bestätigt", + "in_progress": "Es gibt eine Rückfrage der Moderatoren.", "myContributionNoteList": "Eingereichte Beiträge, die noch nicht bestätigt wurden, kannst du jederzeit bearbeiten oder löschen.", - "myContributionNoteSupport": "Es wird bald an dieser Stelle die Möglichkeit geben das ein Dialog zwischen Moderatoren und dir stattfinden kann. Solltest du jetzt Probleme haben bitte nimm Kontakt mit dem Support auf.", "pending": "Eingereicht und wartet auf Bestätigung", "rejected": "abgelehnt" }, @@ -130,6 +132,7 @@ "password_new_repeat": "Neues Passwort wiederholen", "password_old": "Altes Passwort", "recipient": "Empfänger", + "reply": "Antworten", "reset": "Zurücksetzen", "save": "Speichern", "scann_code": "QR Code Scanner - Scanne den QR Code deines Partners", @@ -219,6 +222,7 @@ "email": "Wir haben dir eine E-Mail gesendet.", "errorTitle": "Achtung!", "register": "Du bist jetzt registriert, bitte überprüfe deine Emails und klicke auf den Aktivierungslink.", + "reply": "Danke, Deine Antwort wurde abgesendet.", "reset": "Dein Passwort wurde geändert.", "title": "Danke!", "unsetPassword": "Dein Passwort wurde noch nicht gesetzt. Bitte setze es neu." diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json index 8fe5f31ad..6ec9ef8b8 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -22,6 +22,7 @@ "continue-to-registration": "Continue to registration", "current-community": "Current community", "members": "Members", + "moderator": "Moderator", "moderators": "Moderators", "myContributions": "My contributions to the common good", "openContributionLinks": "open Contribution links list", @@ -34,10 +35,11 @@ "contribution": { "activity": "Activity", "alert": { + "answerQuestion": "Please answer the question", "communityNoteList": "Here you will find all submitted and confirmed contributions from all members of this community.", "confirm": "confirmed", + "in_progress": "There is a question from the moderators.", "myContributionNoteList": "You can edit or delete entries that have not yet been confirmed at any time.", - "myContributionNoteSupport": "Soon there will be the possibility for a dialogue between moderators and you. If you have any problems now, please contact the support.", "pending": "Submitted and waiting for confirmation", "rejected": "deleted" }, @@ -130,6 +132,7 @@ "password_new_repeat": "Repeat new password", "password_old": "Old password", "recipient": "Recipient", + "reply": "Reply", "reset": "Reset", "save": "Save", "scann_code": "QR Code Scanner - Scan the QR Code of your partner", @@ -219,6 +222,7 @@ "email": "We have sent you an email.", "errorTitle": "Attention!", "register": "You are registered now, please check your emails and click the activation link.", + "reply": "Thank you, your reply has been sent.", "reset": "Your password has been changed.", "title": "Thank you!", "unsetPassword": "Your password has not been set yet. Please set it again." diff --git a/frontend/src/locales/es.json b/frontend/src/locales/es.json index f95344b23..939a877f7 100644 --- a/frontend/src/locales/es.json +++ b/frontend/src/locales/es.json @@ -22,6 +22,7 @@ "continue-to-registration": "Continuar con el registro", "current-community": "Comunidad actual", "members": "Miembros", + "moderator": "Moderador", "moderators": "Moderadores", "myContributions": "Mis contribuciones al bien común", "openContributionLinks": "lista de enlaces de contribuciones públicas", @@ -34,10 +35,11 @@ "contribution": { "activity": "Actividad", "alert": { + "answerQuestion": "Por favor, contesta las preguntas", "communityNoteList": "Aquí encontrarás todas las contribuciones enviadas y confirmadas de todos los miembros de esta comunidad.", "confirm": "confirmado", + "in_progress": "Hay una pregunta de los moderatores.", "myContributionNoteList": "Puedes editar o eliminar las contribuciones enviadas que aún no han sido confirmadas en cualquier momento.", - "myContributionNoteSupport": "Pronto existirá la posibilidad de que puedas dialogar con los moderadores. Si tienes algún problema ahora, ponte en contacto con el equipo de asistencia.", "pending": "Enviado y a la espera de confirmación", "rejected": "rechazado" }, @@ -130,6 +132,7 @@ "password_new_repeat": "Repetir contraseña nueva", "password_old": "contraseña antigua", "recipient": "Destinatario", + "reply": "Respuesta", "reset": "Restablecer", "save": "Guardar", "scann_code": "QR Code Scanner - Escanea el código QR de tu pareja", @@ -219,6 +222,7 @@ "email": "Te hemos enviado un correo electrónico.", "errorTitle": "Atención!", "register": "Ya estás registrado, por favor revisa tu correo electrónico y haz clic en el enlace de activación.", + "reply": "Gracias, tu respuesta ha sido enviada.", "reset": "Tu contraseña ha sido cambiada.", "title": "Gracias!", "unsetPassword": "Tu contraseña aún no ha sido configurada. Por favor reinícialo." diff --git a/frontend/src/locales/fr.json b/frontend/src/locales/fr.json index 44a08cd82..07237d16d 100644 --- a/frontend/src/locales/fr.json +++ b/frontend/src/locales/fr.json @@ -22,6 +22,7 @@ "continue-to-registration": "Continuez l´inscription", "current-community": "Communauté actuelle", "members": "Membres", + "moderator": "Modérateur", "moderators": "Modérateurs", "myContributions": "Mes contributions aux biens communs", "openContributionLinks": "liste de liens de contribution publique", @@ -34,10 +35,11 @@ "contribution": { "activity": "Activité", "alert": { + "answerQuestion": "S'il te plais répond à la question", "communityNoteList": "Vous trouverez ci-contre toutes les contributions versées et certifiées de tous les membres de cette communauté.", "confirm": " Approuvé", + "in_progress": "Il y a une question du modérateur.", "myContributionNoteList": "À tout moment vous pouvez éditer ou supprimer les données qui n´ont pas été confirmées.", - "myContributionNoteSupport": "Vous aurez bientôt la possibilité de dialoguer avec un médiateur. Si vous rencontrez un problème maintenant, merci de contacter l´aide en ligne.", "pending": "Inscription en attente de validation", "rejected": "supprimé" }, @@ -130,6 +132,7 @@ "password_new_repeat": "Répétez le nouveau mot de passe", "password_old": "Ancien mot de passe", "recipient": "Destinataire", + "reply": "Répondre", "reset": "Réinitialiser", "save": "Sauvegarder", "scann_code": "QR Code Scanner - Scannez le QR code de votre partenaire", @@ -219,6 +222,7 @@ "email": "Nous vous avons envoyé un email.", "errorTitle": "Attention!", "register": "Vous êtes enregistré maintenant, merci de vérifier votre boîte mail et cliquer sur le lien d´activation.", + "reply": "Merci, ta réponse a été envoyée.", "reset": "Votre mot de passe a été modifié.", "title": "Merci!", "unsetPassword": "Votre mot de passe n´a pas été accepté. Merci de le réinitialiser." diff --git a/frontend/src/locales/nl.json b/frontend/src/locales/nl.json index f817d1458..f84cdaa2a 100644 --- a/frontend/src/locales/nl.json +++ b/frontend/src/locales/nl.json @@ -22,6 +22,7 @@ "continue-to-registration": "Verder ter registratie", "current-community": "Actuele gemeenschap", "members": "Leden", + "moderator": "Moderator", "moderators": "Moderators", "myContributions": "Mijn bijdragen voor het algemeen belang", "openContributionLinks": "openbare lijst van bijdragen", @@ -34,10 +35,11 @@ "contribution": { "activity": "Activiteit", "alert": { + "answerQuestion": "Please answer the question", "communityNoteList": "Hier vind je alle ingediende en bevestigde bijdragen van alle leden uit deze gemeenschap.", "confirm": "bevestigt", + "in_progress": "There is a question from the moderators.", "myContributionNoteList": "Ingediende bijdragen, die nog niet bevestigd zijn, kun je op elk moment wijzigen of verwijderen.", - "myContributionNoteSupport": "Hier heb je binnenkort de mogelijkheid een gesprek met een moderator te voeren. Mocht je nu problemen hebben, dan neem alsjeblieft contact op met Support.", "pending": "Ingediend en wacht op bevestiging", "rejected": "afgewezen" }, @@ -130,6 +132,7 @@ "password_new_repeat": "Nieuw wachtwoord herhalen", "password_old": "Oud wachtwoord", "recipient": "Ontvanger", + "reply": "Antwoord", "reset": "Resetten", "save": "Opslaan", "scann_code": "QR Code Scanner - Scan de QR Code van uw partner", @@ -219,6 +222,7 @@ "email": "We hebben jou een email gestuurd.", "errorTitle": "Opgelet!", "register": "Je bent nu geregistreerd. Controleer alsjeblieft je emails en klik op de activeringslink.", + "reply": "Dank u, uw antwoord is verzonden.", "reset": "Jouw wachtwoord werd gewijzigd.", "title": "Dankjewel!", "unsetPassword": "Jouw wachtwoord werd nog niet ingesteld. Doe het alsjeblieft opnieuw." diff --git a/frontend/src/pages/Community.spec.js b/frontend/src/pages/Community.spec.js index b4aa43785..26d30c1d9 100644 --- a/frontend/src/pages/Community.spec.js +++ b/frontend/src/pages/Community.spec.js @@ -93,9 +93,7 @@ describe('Community', () => { expect(wrapper.findAll('div[role="tabpanel"]')).toHaveLength(3) }) - it('has first tab active by default', () => { - expect(wrapper.findAll('div[role="tabpanel"]').at(0).classes('active')).toBe(true) - }) + it.todo('check for correct tabIndex if state is "IN_PROGRESS" or not') }) describe('API calls after creation', () => { diff --git a/frontend/src/pages/Community.vue b/frontend/src/pages/Community.vue index 64aca6156..8906f40e7 100644 --- a/frontend/src/pages/Community.vue +++ b/frontend/src/pages/Community.vue @@ -2,7 +2,7 @@
- + {{ $t('contribution.alert.pending') }} +
  • + + {{ $t('contribution.alert.in_progress') }} +
  • {{ $t('contribution.alert.confirm') }} @@ -32,9 +36,6 @@

  • -

    - {{ $t('contribution.alert.myContributionNoteSupport') }} -

    item.state === 'IN_PROGRESS')) { + this.tabIndex = 1 + } else { + this.tabIndex = 0 + } }) .catch((err) => { this.toastError(err.message) @@ -258,6 +265,9 @@ export default { updateTransactions(pagination) { this.$emit('update-transactions', pagination) }, + updateState(id) { + this.items.find((item) => item.id === id).state = 'PENDING' + }, }, created() { // verifyLogin is important at this point so that creation is updated on reload if they are deleted in a session in the admin area. @@ -271,6 +281,7 @@ export default { pageSize: this.pageSize, }) this.updateTransactions(0) + this.tabIndex = 1 }, }