+
-
{{ userInitials }}
+
{{ profileInitials }}
@@ -16,7 +16,7 @@
diff --git a/webapp/components/generic/SearchableInput/SearchableInput.vue b/webapp/components/generic/SearchableInput/SearchableInput.vue
index afafa716c..2149732c5 100644
--- a/webapp/components/generic/SearchableInput/SearchableInput.vue
+++ b/webapp/components/generic/SearchableInput/SearchableInput.vue
@@ -35,6 +35,12 @@
>
+
+
+
{
if (!this.isTag(item)) {
this.$router.push({
- name: this.isPost(item) ? 'post-id-slug' : 'profile-id-slug',
+ name: this.getRouteName(item),
params: { id: item.id, slug: item.slug },
})
} else {
diff --git a/webapp/constants/categories.js b/webapp/constants/categories.js
new file mode 100644
index 000000000..64ceb9021
--- /dev/null
+++ b/webapp/constants/categories.js
@@ -0,0 +1,3 @@
+// this file is duplicated in `backend/src/constants/metadata.js` and `webapp/constants/metadata.js`
+export const CATEGORIES_MIN = 1
+export const CATEGORIES_MAX = 3
diff --git a/webapp/constants/groups.js b/webapp/constants/groups.js
new file mode 100644
index 000000000..1c49d3ff3
--- /dev/null
+++ b/webapp/constants/groups.js
@@ -0,0 +1,5 @@
+// this file is duplicated in `backend/src/constants/group.js` and `webapp/constants/group.js`
+export const NAME_LENGTH_MIN = 3
+export const NAME_LENGTH_MAX = 50
+export const DESCRIPTION_WITHOUT_HTML_LENGTH_MIN = 100 // with removed HTML tags
+export const SHOW_GROUP_BUTTON_IN_HEADER = true
diff --git a/webapp/constants/logos.js b/webapp/constants/logos.js
index 136918762..714e78a2c 100644
--- a/webapp/constants/logos.js
+++ b/webapp/constants/logos.js
@@ -4,6 +4,10 @@ export default {
LOGO_HEADER_PATH: '/img/custom/logo-horizontal.svg',
LOGO_HEADER_WIDTH: '130px',
LOGO_HEADER_CLICK: {
+ // externalLink: {
+ // url: 'https://ocelot.social',
+ // target: '_blank',
+ // },
externalLink: null,
internalPath: {
to: {
diff --git a/webapp/graphql/Fragments.js b/webapp/graphql/Fragments.js
index b67851873..23d2c11d3 100644
--- a/webapp/graphql/Fragments.js
+++ b/webapp/graphql/Fragments.js
@@ -12,6 +12,7 @@ export const userFragment = gql`
deleted
}
`
+
export const locationAndBadgesFragment = (lang) => gql`
fragment locationAndBadges on User {
location {
@@ -61,6 +62,29 @@ export const postFragment = gql`
}
`
+export const groupFragment = gql`
+ fragment group on Group {
+ id
+ groupName: name
+ slug
+ disabled
+ deleted
+ about
+ description
+ descriptionExcerpt
+ groupType
+ actionRadius
+ categories {
+ id
+ slug
+ name
+ icon
+ }
+ locationName
+ myRole
+ }
+`
+
export const postCountsFragment = gql`
fragment postCounts on Post {
commentsCount
diff --git a/webapp/graphql/PostMutations.js b/webapp/graphql/PostMutations.js
index ee61efc3b..8880a93b0 100644
--- a/webapp/graphql/PostMutations.js
+++ b/webapp/graphql/PostMutations.js
@@ -3,8 +3,20 @@ import gql from 'graphql-tag'
export default () => {
return {
CreatePost: gql`
- mutation ($title: String!, $content: String!, $categoryIds: [ID], $image: ImageInput) {
- CreatePost(title: $title, content: $content, categoryIds: $categoryIds, image: $image) {
+ mutation (
+ $title: String!
+ $content: String!
+ $categoryIds: [ID]
+ $image: ImageInput
+ $groupId: ID
+ ) {
+ CreatePost(
+ title: $title
+ content: $content
+ categoryIds: $categoryIds
+ image: $image
+ groupId: $groupId
+ ) {
title
slug
content
diff --git a/webapp/graphql/PostQuery.js b/webapp/graphql/PostQuery.js
index 38c90e438..1b5c41984 100644
--- a/webapp/graphql/PostQuery.js
+++ b/webapp/graphql/PostQuery.js
@@ -39,6 +39,11 @@ export default (i18n) => {
...locationAndBadges
}
}
+ group {
+ id
+ name
+ slug
+ }
}
}
`
@@ -64,6 +69,11 @@ export const filterPosts = (i18n) => {
...userCounts
...locationAndBadges
}
+ group {
+ id
+ name
+ slug
+ }
}
}
`
@@ -94,6 +104,11 @@ export const profilePagePosts = (i18n) => {
...userCounts
...locationAndBadges
}
+ group {
+ id
+ name
+ slug
+ }
}
}
`
diff --git a/webapp/graphql/Search.js b/webapp/graphql/Search.js
index 56f5d7c4c..b8c4fcb51 100644
--- a/webapp/graphql/Search.js
+++ b/webapp/graphql/Search.js
@@ -1,9 +1,15 @@
import gql from 'graphql-tag'
-import { userFragment, postFragment, tagsCategoriesAndPinnedFragment } from './Fragments'
+import {
+ userFragment,
+ postFragment,
+ groupFragment,
+ tagsCategoriesAndPinnedFragment,
+} from './Fragments'
export const searchQuery = gql`
${userFragment}
${postFragment}
+ ${groupFragment}
query ($query: String!) {
searchResults(query: $query, limit: 5) {
@@ -24,6 +30,9 @@ export const searchQuery = gql`
... on Tag {
id
}
+ ... on Group {
+ ...group
+ }
}
}
`
@@ -52,6 +61,46 @@ export const searchPosts = gql`
}
`
+export const searchGroups = (i18n) => {
+ const lang = i18n ? i18n.locale().toUpperCase() : 'EN'
+ return gql`
+ query ($query: String!, $firstGroups: Int, $groupsOffset: Int) {
+ searchGroups(query: $query, firstGroups: $firstGroups, groupsOffset: $groupsOffset) {
+ groupCount
+ groups {
+ __typename
+ id
+ groupName: name
+ slug
+ createdAt
+ updatedAt
+ disabled
+ deleted
+ about
+ description
+ descriptionExcerpt
+ groupType
+ actionRadius
+ categories {
+ id
+ slug
+ name
+ icon
+ }
+ avatar {
+ url
+ }
+ locationName
+ location {
+ name: name${lang}
+ }
+ myRole
+ }
+ }
+ }
+ `
+}
+
export const searchUsers = gql`
${userFragment}
diff --git a/webapp/graphql/User.js b/webapp/graphql/User.js
index 053cb022f..0d3a24d8b 100644
--- a/webapp/graphql/User.js
+++ b/webapp/graphql/User.js
@@ -49,8 +49,8 @@ export default (i18n) => {
export const minimisedUserQuery = () => {
return gql`
- query {
- User(orderBy: slug_asc) {
+ query ($slug: String) {
+ User(slug: $slug, orderBy: slug_asc) {
id
slug
name
@@ -221,25 +221,25 @@ export const updateUserMutation = () => {
$id: ID!
$slug: String
$name: String
- $locationName: String
$about: String
$allowEmbedIframes: Boolean
$showShoutsPublicly: Boolean
$sendNotificationEmails: Boolean
$termsAndConditionsAgreedVersion: String
$avatar: ImageInput
+ $locationName: String # empty string '' sets it to null
) {
UpdateUser(
id: $id
slug: $slug
name: $name
- locationName: $locationName
about: $about
allowEmbedIframes: $allowEmbedIframes
showShoutsPublicly: $showShoutsPublicly
sendNotificationEmails: $sendNotificationEmails
termsAndConditionsAgreedVersion: $termsAndConditionsAgreedVersion
avatar: $avatar
+ locationName: $locationName
) {
id
slug
diff --git a/webapp/graphql/groups.js b/webapp/graphql/groups.js
new file mode 100644
index 000000000..e3510c74d
--- /dev/null
+++ b/webapp/graphql/groups.js
@@ -0,0 +1,200 @@
+import gql from 'graphql-tag'
+
+// ------ mutations
+
+export const createGroupMutation = () => {
+ return gql`
+ mutation (
+ $id: ID
+ $name: String!
+ $slug: String
+ $about: String
+ $description: String!
+ $groupType: GroupType!
+ $actionRadius: GroupActionRadius!
+ $categoryIds: [ID]
+ $locationName: String # empty string '' sets it to null
+ ) {
+ CreateGroup(
+ id: $id
+ name: $name
+ slug: $slug
+ about: $about
+ description: $description
+ groupType: $groupType
+ actionRadius: $actionRadius
+ categoryIds: $categoryIds
+ locationName: $locationName
+ ) {
+ id
+ name
+ slug
+ createdAt
+ updatedAt
+ disabled
+ deleted
+ about
+ description
+ descriptionExcerpt
+ groupType
+ actionRadius
+ categories {
+ id
+ slug
+ name
+ icon
+ }
+ locationName
+ myRole
+ }
+ }
+ `
+}
+
+export const updateGroupMutation = () => {
+ return gql`
+ mutation (
+ $id: ID!
+ $name: String
+ $slug: String
+ $about: String
+ $description: String
+ $actionRadius: GroupActionRadius
+ $categoryIds: [ID]
+ $avatar: ImageInput
+ $locationName: String # empty string '' sets it to null
+ ) {
+ UpdateGroup(
+ id: $id
+ name: $name
+ slug: $slug
+ about: $about
+ description: $description
+ actionRadius: $actionRadius
+ categoryIds: $categoryIds
+ avatar: $avatar
+ locationName: $locationName
+ ) {
+ id
+ name
+ slug
+ createdAt
+ updatedAt
+ disabled
+ deleted
+ about
+ description
+ descriptionExcerpt
+ groupType
+ actionRadius
+ categories {
+ id
+ slug
+ name
+ icon
+ }
+ # avatar # test this as result
+ locationName
+ myRole
+ }
+ }
+ `
+}
+
+export const joinGroupMutation = () => {
+ return gql`
+ mutation ($groupId: ID!, $userId: ID!) {
+ JoinGroup(groupId: $groupId, userId: $userId) {
+ id
+ name
+ slug
+ myRoleInGroup
+ }
+ }
+ `
+}
+
+export const leaveGroupMutation = () => {
+ return gql`
+ mutation ($groupId: ID!, $userId: ID!) {
+ LeaveGroup(groupId: $groupId, userId: $userId) {
+ id
+ name
+ slug
+ myRoleInGroup
+ }
+ }
+ `
+}
+
+export const changeGroupMemberRoleMutation = () => {
+ return gql`
+ mutation ($groupId: ID!, $userId: ID!, $roleInGroup: GroupMemberRole!) {
+ ChangeGroupMemberRole(groupId: $groupId, userId: $userId, roleInGroup: $roleInGroup) {
+ id
+ name
+ slug
+ myRoleInGroup
+ }
+ }
+ `
+}
+
+// ------ queries
+
+export const groupQuery = (i18n) => {
+ const lang = i18n ? i18n.locale().toUpperCase() : 'EN'
+ return gql`
+ query ($isMember: Boolean, $id: ID, $slug: String, $first: Int, $offset: Int) {
+ Group(isMember: $isMember, id: $id, slug: $slug, first: $first, offset: $offset) {
+ id
+ name
+ slug
+ createdAt
+ updatedAt
+ disabled
+ deleted
+ about
+ description
+ descriptionExcerpt
+ groupType
+ actionRadius
+ categories {
+ id
+ slug
+ name
+ icon
+ }
+ avatar {
+ url
+ }
+ locationName
+ location {
+ name: name${lang}
+ }
+ myRole
+ }
+ }
+ `
+}
+
+export const groupMembersQuery = () => {
+ return gql`
+ query ($id: ID!) {
+ GroupMembers(id: $id) {
+ id
+ name
+ slug
+ myRoleInGroup
+ }
+ }
+ `
+}
+
+export const groupCountQuery = () => {
+ return gql`
+ query ($isMember: Boolean) {
+ GroupCount(isMember: $isMember)
+ }
+ `
+}
diff --git a/webapp/locales/de.json b/webapp/locales/de.json
index 753b2e9d1..39fd2de9f 100644
--- a/webapp/locales/de.json
+++ b/webapp/locales/de.json
@@ -357,15 +357,16 @@
"placeholder": "Schreib etwas Inspirierendes …"
},
"error-pages": {
- "403-default": "Kein Zugang zu dieser Seite",
- "404-default": "Diese Seite konnte nicht gefunden werden",
- "500-default": "Internal Server Error",
- "503-default": "Dienst steht nicht zur Verfügung",
- "back-to-index": "Zurück zur Startseite",
- "cannot-edit-post": "Dieser Beitrag kann nicht editiert werden",
- "default": "Ein Fehler ist aufgetreten",
- "post-not-found": "Dieser Beitrag konnte nicht gefunden werden",
- "profile-not-found": "Dieses Profil konnte nicht gefunden werden"
+ "403-default": "Kein Zugang zu dieser Seite!",
+ "404-default": "Diese Seite konnte nicht gefunden werden!",
+ "500-default": "Internal Server Error!",
+ "503-default": "Dienst steht nicht zur Verfügung!",
+ "back-to-index": "Zurück zur Startseite!",
+ "cannot-edit-post": "Dieser Beitrag kann nicht editiert werden!",
+ "default": "Ein Fehler ist aufgetreten!",
+ "group-not-found": "Dieses Gruppenprofil konnte nicht gefunden werden!",
+ "post-not-found": "Dieser Beitrag konnte nicht gefunden werden!",
+ "profile-not-found": "Dieses Profil konnte nicht gefunden werden!"
},
"filter-menu": {
"all": "Alle",
@@ -394,11 +395,92 @@
"follow": "Folgen",
"following": "Folge Ich"
},
+ "group": {
+ "actionRadii": {
+ "continental": "Kontinentale Gruppe",
+ "global": "Globale Gruppe",
+ "interplanetary": "Interplanetare Gruppe",
+ "national": "Nationale Gruppe",
+ "regional": "Regionale Gruppe"
+ },
+ "actionRadius": "Aktionsradius",
+ "addMemberToGroup": "Zur Gruppe hinzufügen",
+ "addUser": "Benutzer hinzufügen",
+ "addUserPlaceholder": "eindeutiger Benutzername > @slug-from-user",
+ "allGroups": "Alle Gruppen",
+ "categories": "Thema ::: Themen",
+ "changeMemberRole": "Die Rolle wurde auf „{role}“ geändert!",
+ "contentMenu": {
+ "visitGroupPage": "Gruppe anzeigen"
+ },
+ "createNewGroup": {
+ "title": "Erstelle eine neue Gruppe",
+ "tooltip": "Erstelle eine neue Gruppe"
+ },
+ "description": "Beschreibung",
+ "editGroupSettings": {
+ "groupName": "Einstellungen für „{name}“",
+ "title": "Meine Gruppe ändern"
+ },
+ "follow": "Folge",
+ "foundation": "Gründung",
+ "general": "Allgemein",
+ "goal": "Ziel der Gruppe",
+ "groupCreated": "Die Gruppe wurde angelegt!",
+ "in": "in",
+ "joinLeaveButton": {
+ "iAmMember": "Bin Mitglied",
+ "join": "Beitreten"
+ },
+ "labelSlug": "Eindeutiger Gruppenname",
+ "leaveModal": {
+ "confirmButton": "Verlassen",
+ "message": "Eine Gruppe zu verlassen ist möglicherweise nicht rückgängig zu machen! Gruppe „{name}“ verlassen!",
+ "title": "Möchtest du wirklich die Gruppe verlassen?"
+ },
+ "members": "Mitglieder",
+ "membersAdministrationList": {
+ "avatar": "Avatar",
+ "name": "Name",
+ "roleInGroup": "Rolle",
+ "slug": "Eindeutiger Name"
+ },
+ "membersCount": "Mitglied ::: Mitglieder",
+ "membersListTitle": "Gruppenmitglieder",
+ "membersListTitleNotAllowedSeeingGroupMembers": "Gruppenmitglieder unsichtbar",
+ "myGroups": "Meine Gruppen",
+ "name": "Gruppenname",
+ "radius": "Radius",
+ "removeMember": "Mitglied aus der Gruppe entfernen?",
+ "removeMemberButton": "Entfernen",
+ "role": "Deine Rolle in der Gruppe",
+ "roles": {
+ "admin": "Administrator",
+ "owner": "Inhaber",
+ "pending": "Ausstehendes Mitglied",
+ "usual": "Einfaches Mitglied"
+ },
+ "save": "Neue Gruppe anlegen",
+ "type": "Gruppentyp",
+ "types": {
+ "closed": "Geschlossene Gruppe",
+ "hidden": "Versteckte Gruppe",
+ "public": "Öffentliche Gruppe"
+ },
+ "update": "Änderung speichern",
+ "updatedGroup": "Die Gruppendaten wurden geändert!"
+ },
"hashtags-filter": {
"clearSearch": "Suche löschen",
"hashtag-search": "Suche nach #{hashtag}",
"title": "Deine Filterblase"
},
+ "header": {
+ "avatarMenu": {
+ "Groups": "Gruppen",
+ "myProfile": "Mein Profil"
+ }
+ },
"index": {
"change-filter-settings": "Verändere die Filter-Einstellungen, um mehr Ergebnisse zu erhalten.",
"no-results": "Keine Beiträge gefunden."
@@ -528,7 +610,19 @@
"submitted": "Kommentar gesendet",
"updated": "Änderungen gespeichert"
},
+ "createNewPost": {
+ "forGroup": {
+ "title": "Für die Gruppe „{name}“"
+ },
+ "title": "Erstelle einen neuen Beitrag"
+ },
"edited": "bearbeitet",
+ "editPost": {
+ "forGroup": {
+ "title": "Für die Gruppe „{name}“"
+ },
+ "title": "Bearbeite deinen Beitrag"
+ },
"menu": {
"delete": "Beitrag löschen",
"edit": "Beitrag bearbeiten",
@@ -541,9 +635,18 @@
"pinned": "Meldung",
"takeAction": {
"name": "Aktiv werden"
+ },
+ "viewPost": {
+ "forGroup": {
+ "title": "In der Gruppe „{name}“"
+ },
+ "title": "Beitrag"
}
},
"profile": {
+ "avatar": {
+ "submitted": "Erfolgreich hochgeladen!"
+ },
"commented": "Kommentiert",
"follow": "Folgen",
"followers": "Folgen",
@@ -554,7 +657,6 @@
"title": "Lade jemanden zu {APPLICATION_NAME} ein!"
},
"memberSince": "Mitglied seit",
- "name": "Mein Profil",
"network": {
"andMore": "und {number} weitere …",
"followedBy": "wird gefolgt von:",
@@ -644,11 +746,12 @@
"failed": "Nichts gefunden",
"for": "Suche nach ",
"heading": {
+ "Group": "Gruppe ::: Gruppen",
"Post": "Beitrag ::: Beiträge",
"Tag": "Hashtag ::: Hashtags",
"User": "Benutzer ::: Benutzer"
},
- "hint": "Wonach suchst Du? Nutze !… für Beiträge, @… für Mitglieder, #… für Hashtags",
+ "hint": "Wonach suchst Du? Nutze !… für Beiträge, @… für Mitglieder, &… für Gruppen, #… für Hashtags",
"no-results": "Keine Ergebnisse für \"{search}\" gefunden. Versuch' es mit einem anderen Begriff!",
"page": "Seite",
"placeholder": "Suchen",
@@ -845,10 +948,5 @@
"newTermsAndConditions": "Neue Nutzungsbedingungen",
"termsAndConditionsNewConfirm": "Ich habe die neuen Nutzungsbedingungen durchgelesen und stimme zu.",
"termsAndConditionsNewConfirmText": "Bitte lies Dir die neuen Nutzungsbedingungen jetzt durch!"
- },
- "user": {
- "avatar": {
- "submitted": "Erfolgreich hochgeladen!"
- }
}
}
diff --git a/webapp/locales/en.json b/webapp/locales/en.json
index f2a6c3fc2..18b579df4 100644
--- a/webapp/locales/en.json
+++ b/webapp/locales/en.json
@@ -357,15 +357,16 @@
"placeholder": "Leave your inspirational thoughts …"
},
"error-pages": {
- "403-default": "Not authorized to this page",
- "404-default": "This page could not be found",
- "500-default": "Internal Server Error",
- "503-default": "Service Unavailable",
- "back-to-index": "Back to index page",
- "cannot-edit-post": "This post cannot be edited",
- "default": "An error occurred",
- "post-not-found": "This post could not be found",
- "profile-not-found": "This profile could not be found"
+ "403-default": "Not authorized to this page!",
+ "404-default": "This page could not be found!",
+ "500-default": "Internal Server Error!",
+ "503-default": "Service Unavailable!",
+ "back-to-index": "Back to index page!",
+ "cannot-edit-post": "This post cannot be edited!",
+ "default": "An error occurred!",
+ "group-not-found": "This group profile could not be found!",
+ "post-not-found": "This post could not be found!",
+ "profile-not-found": "This profile could not be found!"
},
"filter-menu": {
"all": "All",
@@ -394,11 +395,92 @@
"follow": "Follow",
"following": "Following"
},
+ "group": {
+ "actionRadii": {
+ "continental": "Continental Group",
+ "global": "Global Group",
+ "interplanetary": "Interplanetary Group",
+ "national": "National Group",
+ "regional": "Regional Group"
+ },
+ "actionRadius": "Action radius",
+ "addMemberToGroup": "Add to group",
+ "addUser": "Add User",
+ "addUserPlaceholder": "unique username > @slug-from-user",
+ "allGroups": "All Groups",
+ "categories": "Topic ::: Topics",
+ "changeMemberRole": "The role has been changed to “{role}”!",
+ "contentMenu": {
+ "visitGroupPage": "Show group"
+ },
+ "createNewGroup": {
+ "title": "Create A New Group",
+ "tooltip": "Create a new group"
+ },
+ "description": "Description",
+ "editGroupSettings": {
+ "groupName": "Settings Of “{name}”",
+ "title": "Edit My Group"
+ },
+ "follow": "Follow",
+ "foundation": "Foundation",
+ "general": "General",
+ "goal": "Goal of group",
+ "groupCreated": "The group was created!",
+ "in": "in",
+ "joinLeaveButton": {
+ "iAmMember": "I'm a member",
+ "join": "Join"
+ },
+ "labelSlug": "Unique group name",
+ "leaveModal": {
+ "confirmButton": "Leave",
+ "message": "Leaving a group may be irreversible! Leave group “{name}” !",
+ "title": "Do you really want to leave the group?"
+ },
+ "members": "Members",
+ "membersAdministrationList": {
+ "avatar": "Avatar",
+ "name": "Name",
+ "roleInGroup": "Role",
+ "slug": "Unique name"
+ },
+ "membersCount": "Member ::: Members",
+ "membersListTitle": "Group Members",
+ "membersListTitleNotAllowedSeeingGroupMembers": "Group Members invisible",
+ "myGroups": "My Groups",
+ "name": "Group name",
+ "radius": "Radius",
+ "removeMember": "Remove member",
+ "removeMemberButton": "Remove",
+ "role": "Your role in the group",
+ "roles": {
+ "admin": "Administrator",
+ "owner": "Owner",
+ "pending": "Pending Member",
+ "usual": "Simple Member"
+ },
+ "save": "Create new group",
+ "type": "Group type",
+ "types": {
+ "closed": "Closed Group",
+ "hidden": "Hidden Group",
+ "public": "Public Group"
+ },
+ "update": "Save change",
+ "updatedGroup": "The group data has been changed."
+ },
"hashtags-filter": {
"clearSearch": "Clear search",
"hashtag-search": "Searching for #{hashtag}",
"title": "Your filter bubble"
},
+ "header": {
+ "avatarMenu": {
+ "Groups": "Groups",
+ "myProfile": "My profile"
+ }
+ },
"index": {
"change-filter-settings": "Change your filter settings to get more results.",
"no-results": "No contributions found."
@@ -528,7 +610,19 @@
"submitted": "Comment submitted!",
"updated": "Changes saved!"
},
+ "createNewPost": {
+ "forGroup": {
+ "title": "For The Group “{name}”"
+ },
+ "title": "Create A New Post"
+ },
"edited": "edited",
+ "editPost": {
+ "forGroup": {
+ "title": "For The Group “{name}”"
+ },
+ "title": "Edit Your Post"
+ },
"menu": {
"delete": "Delete post",
"edit": "Edit post",
@@ -541,9 +635,18 @@
"pinned": "Announcement",
"takeAction": {
"name": "Take action"
+ },
+ "viewPost": {
+ "forGroup": {
+ "title": "In The Group “{name}”"
+ },
+ "title": "Post"
}
},
"profile": {
+ "avatar": {
+ "submitted": "Upload successful!"
+ },
"commented": "Commented",
"follow": "Follow",
"followers": "Followers",
@@ -554,7 +657,6 @@
"title": "Invite somebody to {APPLICATION_NAME}!"
},
"memberSince": "Member since",
- "name": "My Profile",
"network": {
"andMore": "and {number} more …",
"followedBy": "is followed by:",
@@ -644,11 +746,12 @@
"failed": "Nothing found",
"for": "Searching for ",
"heading": {
+ "Group": "Group ::: Groups",
"Post": "Post ::: Posts",
"Tag": "Hashtag ::: Hashtags",
"User": "User ::: Users"
},
- "hint": "What are you searching for? Use !… for posts, @… for users, #… for hashtags.",
+ "hint": "What are you searching for? Use !… for posts, @… for users, &… for groups, #… for hashtags.",
"no-results": "No results found for \"{search}\". Try a different search term!",
"page": "Page",
"placeholder": "Search",
@@ -845,10 +948,5 @@
"newTermsAndConditions": "New Terms and Conditions",
"termsAndConditionsNewConfirm": "I have read and agree to the new terms of conditions.",
"termsAndConditionsNewConfirmText": "Please read the new terms of use now!"
- },
- "user": {
- "avatar": {
- "submitted": "Upload successful!"
- }
}
}
diff --git a/webapp/locales/es.json b/webapp/locales/es.json
index 900b2fa5d..63070ee4b 100644
--- a/webapp/locales/es.json
+++ b/webapp/locales/es.json
@@ -297,6 +297,16 @@
"follow": "Seguir",
"following": "Siguiendo"
},
+ "group": {
+ "foundation": null,
+ "goal": null,
+ "joinLeaveButton": {
+ "iAmMember": null,
+ "join": null
+ },
+ "membersCount": null,
+ "membersListTitle": null
+ },
"hashtags-filter": {
"clearSearch": "Borrar búsqueda",
"hashtag-search": "Buscando a #{hashtag}",
@@ -435,6 +445,9 @@
}
},
"profile": {
+ "avatar": {
+ "submitted": "Carga con éxito"
+ },
"commented": "Comentado",
"follow": "Seguir",
"followers": "Seguidores",
@@ -715,10 +728,5 @@
"newTermsAndConditions": "Nuevos términos de uso",
"termsAndConditionsNewConfirm": "He leído y acepto los nuevos términos de uso.",
"termsAndConditionsNewConfirmText": "¡Por favor, lea los nuevos términos de uso ahora!"
- },
- "user": {
- "avatar": {
- "submitted": "Carga con éxito"
- }
}
}
diff --git a/webapp/locales/fr.json b/webapp/locales/fr.json
index 684f080b7..91b91abe9 100644
--- a/webapp/locales/fr.json
+++ b/webapp/locales/fr.json
@@ -286,6 +286,16 @@
"follow": "Suivre",
"following": "Je suis les"
},
+ "group": {
+ "foundation": null,
+ "goal": null,
+ "joinLeaveButton": {
+ "iAmMember": null,
+ "join": null
+ },
+ "membersCount": null,
+ "membersListTitle": null
+ },
"hashtags-filter": {
"clearSearch": "Réinitialiser la recherche",
"hashtag-search": "Recherche de #{hashtag}",
@@ -423,6 +433,9 @@
}
},
"profile": {
+ "avatar": {
+ "submitted": "Téléchargement réussi"
+ },
"commented": "Commentais",
"follow": "Suivre",
"followers": "Suiveurs",
@@ -683,10 +696,5 @@
"newTermsAndConditions": "Nouvelles conditions générales",
"termsAndConditionsNewConfirm": "J'ai lu et accepté les nouvelles conditions générales.",
"termsAndConditionsNewConfirmText": "Veuillez lire les nouvelles conditions d'utilisation dès maintenant !"
- },
- "user": {
- "avatar": {
- "submitted": "Téléchargement réussi"
- }
}
}
diff --git a/webapp/locales/it.json b/webapp/locales/it.json
index 71994167b..342550a14 100644
--- a/webapp/locales/it.json
+++ b/webapp/locales/it.json
@@ -294,6 +294,16 @@
"follow": null,
"following": null
},
+ "group": {
+ "foundation": null,
+ "goal": null,
+ "joinLeaveButton": {
+ "iAmMember": null,
+ "join": null
+ },
+ "membersCount": null,
+ "membersListTitle": null
+ },
"hashtags-filter": {
"clearSearch": null,
"hashtag-search": null,
@@ -376,6 +386,9 @@
}
},
"profile": {
+ "avatar": {
+ "submitted": null
+ },
"commented": "Commentato",
"follow": "Seguire",
"followers": "Seguenti",
@@ -633,10 +646,5 @@
"newTermsAndConditions": "Nuovi Termini e Condizioni",
"termsAndConditionsNewConfirm": "Ho letto e accetto le nuove condizioni generali di contratto.",
"termsAndConditionsNewConfirmText": "Si prega di leggere le nuove condizioni d'uso ora!"
- },
- "user": {
- "avatar": {
- "submitted": null
- }
}
}
diff --git a/webapp/locales/nl.json b/webapp/locales/nl.json
index 3c1a8902d..c7e474a3a 100644
--- a/webapp/locales/nl.json
+++ b/webapp/locales/nl.json
@@ -82,6 +82,16 @@
"follow": "Volgen",
"following": "Volgt"
},
+ "group": {
+ "foundation": null,
+ "goal": null,
+ "joinLeaveButton": {
+ "iAmMember": null,
+ "join": null
+ },
+ "membersCount": null,
+ "membersListTitle": null
+ },
"login": {
"email": "Uw E-mail",
"hello": "Hallo",
@@ -100,6 +110,9 @@
}
},
"profile": {
+ "avatar": {
+ "submitted": null
+ },
"follow": "Volgen",
"followers": "Volgelingen",
"following": "Volgt",
diff --git a/webapp/locales/pl.json b/webapp/locales/pl.json
index 6ae3e32f7..840698487 100644
--- a/webapp/locales/pl.json
+++ b/webapp/locales/pl.json
@@ -166,6 +166,16 @@
"follow": "naśladować",
"following": "w skutek"
},
+ "group": {
+ "foundation": null,
+ "goal": null,
+ "joinLeaveButton": {
+ "iAmMember": null,
+ "join": null
+ },
+ "membersCount": null,
+ "membersListTitle": null
+ },
"hashtags-filter": {
"title": "Twoja bańka filtrująca"
},
@@ -208,6 +218,9 @@
}
},
"profile": {
+ "avatar": {
+ "submitted": "Przesłano pomyślnie"
+ },
"commented": "Skomentuj",
"follow": "Obserwuj",
"followers": "Obserwujący",
@@ -356,10 +369,5 @@
"taxident": "Numer identyfikacyjny podatku od wartości dodanej zgodnie z § 27 a Ustawa o podatku od wartości dodanej (Niemcy)",
"termsAc": "Warunki użytkowania",
"tribunal": "sąd rejestrowy"
- },
- "user": {
- "avatar": {
- "submitted": "Przesłano pomyślnie"
- }
}
}
diff --git a/webapp/locales/pt.json b/webapp/locales/pt.json
index f5f89374a..bec922edb 100644
--- a/webapp/locales/pt.json
+++ b/webapp/locales/pt.json
@@ -332,6 +332,16 @@
"follow": "Seguir",
"following": "Seguindo"
},
+ "group": {
+ "foundation": null,
+ "goal": null,
+ "joinLeaveButton": {
+ "iAmMember": null,
+ "join": null
+ },
+ "membersCount": null,
+ "membersListTitle": null
+ },
"hashtags-filter": {
"clearSearch": "Limpar pesquisa",
"hashtag-search": "Procurando por #{hashtag}",
@@ -412,6 +422,9 @@
}
},
"profile": {
+ "avatar": {
+ "submitted": "Carregado com sucesso!"
+ },
"commented": "Comentou",
"follow": "Seguir",
"followers": "Seguidores",
@@ -668,10 +681,5 @@
"newTermsAndConditions": "Novos Termos e Condições",
"termsAndConditionsNewConfirm": "Eu li e concordo com os novos termos de condições.",
"termsAndConditionsNewConfirmText": "Por favor, leia os novos termos de uso agora!"
- },
- "user": {
- "avatar": {
- "submitted": "Carregado com sucesso!"
- }
}
}
diff --git a/webapp/locales/ru.json b/webapp/locales/ru.json
index 5f1368820..f50121635 100644
--- a/webapp/locales/ru.json
+++ b/webapp/locales/ru.json
@@ -311,6 +311,16 @@
"follow": "Подписаться",
"following": "Вы подписаны"
},
+ "group": {
+ "foundation": null,
+ "goal": null,
+ "joinLeaveButton": {
+ "iAmMember": null,
+ "join": null
+ },
+ "membersCount": null,
+ "membersListTitle": null
+ },
"hashtags-filter": {
"clearSearch": "Очистить поиск",
"hashtag-search": "Поиск по #{hashtag}",
@@ -449,6 +459,9 @@
}
},
"profile": {
+ "avatar": {
+ "submitted": "Успешная загрузка!"
+ },
"commented": "Прокомментированные",
"follow": "Подписаться",
"followers": "Подписчики",
@@ -729,10 +742,5 @@
"newTermsAndConditions": "Новые условия и положения",
"termsAndConditionsNewConfirm": "Я прочитал(а) и согласен(на) с новыми условиями.",
"termsAndConditionsNewConfirmText": "Пожалуйста, ознакомьтесь с новыми условиями использования!"
- },
- "user": {
- "avatar": {
- "submitted": "Успешная загрузка!"
- }
}
}
diff --git a/webapp/maintenance/source/package.json b/webapp/maintenance/source/package.json
index 127fba57c..7b2cf294c 100644
--- a/webapp/maintenance/source/package.json
+++ b/webapp/maintenance/source/package.json
@@ -1,6 +1,6 @@
{
"name": "@ocelot-social/maintenance",
- "version": "1.1.1",
+ "version": "2.1.0",
"description": "Maintenance page for ocelot.social",
"repository": "https://github.com/Ocelot-Social-Community/Ocelot-Social",
"author": "ocelot.social Community",
diff --git a/webapp/mixins/persistentLinks.js b/webapp/mixins/persistentLinks.js
index 0abe37c03..164ccea41 100644
--- a/webapp/mixins/persistentLinks.js
+++ b/webapp/mixins/persistentLinks.js
@@ -10,22 +10,24 @@ export default function (options = {}) {
} = context
const idOrSlug = id || slug
- const variables = { idOrSlug }
- const client = apolloProvider.defaultClient
+ if (idOrSlug) {
+ const variables = { idOrSlug }
+ const client = apolloProvider.defaultClient
- let response
- let resource
- response = await client.query({ query: queryId, variables })
- resource = response.data[Object.keys(response.data)[0]][0]
- if (resource && resource.slug === slug) return // all good
- if (resource && resource.slug !== slug) {
- return redirect(`/${path}/${resource.id}/${resource.slug}`)
+ let response
+ let resource
+ response = await client.query({ query: queryId, variables })
+ resource = response.data[Object.keys(response.data)[0]][0]
+ if (resource && resource.slug === slug) return // all good
+ if (resource && resource.slug !== slug) {
+ return redirect(`/${path}/${resource.id}/${resource.slug}`)
+ }
+
+ response = await client.query({ query: querySlug, variables })
+ resource = response.data[Object.keys(response.data)[0]][0]
+ if (resource) return redirect(`/${path}/${resource.id}/${resource.slug}`)
}
- response = await client.query({ query: querySlug, variables })
- resource = response.data[Object.keys(response.data)[0]][0]
- if (resource) return redirect(`/${path}/${resource.id}/${resource.slug}`)
-
return error({ statusCode: 404, key: message })
},
}
diff --git a/webapp/package.json b/webapp/package.json
index f62efebab..7b86d4d92 100644
--- a/webapp/package.json
+++ b/webapp/package.json
@@ -1,6 +1,6 @@
{
"name": "ocelot-social-webapp",
- "version": "1.1.1",
+ "version": "2.1.0",
"description": "ocelot.social Frontend",
"repository": "https://github.com/Ocelot-Social-Community/Ocelot-Social",
"author": "ocelot.social Community",
diff --git a/webapp/pages/group/_id.spec.js b/webapp/pages/group/_id.spec.js
new file mode 100644
index 000000000..bafd5c392
--- /dev/null
+++ b/webapp/pages/group/_id.spec.js
@@ -0,0 +1,33 @@
+import { config, mount } from '@vue/test-utils'
+import _id from './_id.vue'
+
+const localVue = global.localVue
+
+config.stubs['nuxt-child'] = ' '
+
+describe('Group profile _id.vue', () => {
+ let wrapper
+ let Wrapper
+ let mocks
+
+ beforeEach(() => {
+ mocks = {}
+ })
+
+ describe('mount', () => {
+ Wrapper = () => {
+ return mount(_id, {
+ mocks,
+ localVue,
+ })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders', () => {
+ expect(wrapper.findAll('.nuxt-child')).toHaveLength(1)
+ })
+ })
+})
diff --git a/webapp/pages/group/_id.vue b/webapp/pages/group/_id.vue
new file mode 100644
index 000000000..d743633d1
--- /dev/null
+++ b/webapp/pages/group/_id.vue
@@ -0,0 +1,34 @@
+
+
+
+
+
diff --git a/webapp/pages/group/_id/_slug.spec.js b/webapp/pages/group/_id/_slug.spec.js
new file mode 100644
index 000000000..963952f5e
--- /dev/null
+++ b/webapp/pages/group/_id/_slug.spec.js
@@ -0,0 +1,1635 @@
+import { config, mount } from '@vue/test-utils'
+import GroupProfileSlug from './_slug.vue'
+
+const localVue = global.localVue
+
+localVue.filter('date', (d) => d)
+
+config.stubs['client-only'] = ' '
+config.stubs['v-popover'] = ' '
+config.stubs['nuxt-link'] = ' '
+config.stubs['infinite-loading'] = ' '
+config.stubs['follow-list'] = ' '
+
+describe('GroupProfileSlug', () => {
+ let wrapper
+ let Wrapper
+ let mocks
+ let yogaPractice
+ let schoolForCitizens
+ let investigativeJournalism
+ let peterLustig
+ let jennyRostock
+ let bobDerBaumeister
+ let huey
+
+ beforeEach(() => {
+ mocks = {
+ $env: {
+ CATEGORIES_ACTIVE: true,
+ },
+ // post: {
+ // id: 'p23',
+ // name: 'It is a post',
+ // },
+ $t: jest.fn((a) => a),
+ $filters: {
+ removeLinks: (c) => c,
+ truncate: (a) => a,
+ },
+ // If you're mocking router, then don't use VueRouter with localVue: https://vue-test-utils.vuejs.org/guides/using-with-vue-router.html
+ $route: {
+ params: {
+ id: 'g1',
+ slug: 'school-for-citizens',
+ },
+ },
+ $router: {
+ history: {
+ push: jest.fn(),
+ },
+ },
+ $toast: {
+ success: jest.fn(),
+ error: jest.fn(),
+ },
+ $apollo: {
+ loading: false,
+ mutate: jest.fn().mockResolvedValue(),
+ },
+ }
+ yogaPractice = {
+ id: 'g2',
+ name: 'Yoga Practice',
+ slug: 'yoga-practice',
+ about: null,
+ description: `
What Is yoga? Yoga is not just about practicing asanas. It's about how we do it.
And practicing asanas doesn't have to be yoga, it can be more athletic than yogic.
What makes practicing asanas yogic? The important thing is:
`,
+ descriptionExcerpt: `
What Is yoga? Yoga is not just about practicing asanas. It's about how we do it.
And practicing asanas doesn't have to be yoga, it can be more athletic than yogic.
What makes practicing asanas yogic? The important thing is:
`,
+ groupType: 'public',
+ actionRadius: 'interplanetary',
+ categories: [
+ {
+ id: 'cat4',
+ icon: 'psyche',
+ name: 'psyche',
+ slug: 'psyche',
+ description: 'Seele, Gefühle, Glück',
+ },
+ {
+ id: 'cat5',
+ icon: 'movement',
+ name: 'body-and-excercise',
+ slug: 'body-and-excercise',
+ description: 'Sport, Yoga, Massage, Tanzen, Entspannung',
+ },
+ {
+ id: 'cat17',
+ icon: 'spirituality',
+ name: 'spirituality',
+ slug: 'spirituality',
+ description: 'Religion, Werte, Ethik',
+ },
+ ],
+ locationName: null,
+ location: null,
+ // myRole: 'usual',
+ }
+ schoolForCitizens = {
+ id: 'g1',
+ name: 'School For Citizens',
+ slug: 'school-for-citizens',
+ about: 'Our children shall receive education for life.',
+ description: `
English
Our goal Only those who enjoy learning and do not lose their curiosity can obtain a good education for life and continue to learn with joy throughout their lives.
Curiosity For this we need a school that takes up the curiosity of the children, the people, and satisfies it through a lot of experience.
Deutsch
Unser Ziel Nur wer Spaß am Lernen hat und seine Neugier nicht verliert, kann gute Bildung für's Leben erlangen und sein ganzes Leben mit Freude weiter lernen.
Neugier Dazu benötigen wir eine Schule, die die Neugier der Kinder, der Menschen, aufnimmt und durch viel Erfahrung befriedigt.
`,
+ descriptionExcerpt: `
English
Our goal Only those who enjoy learning and do not lose their curiosity can obtain a good education for life and continue to learn with joy throughout their lives.
Curiosity For this we need a school that takes up the curiosity of the children, …
`,
+ groupType: 'closed',
+ actionRadius: 'national',
+ categories: [
+ {
+ id: 'cat8',
+ icon: 'child',
+ name: 'children',
+ slug: 'children',
+ description: 'Familie, Pädagogik, Schule, Prägung',
+ },
+ {
+ id: 'cat14',
+ icon: 'science',
+ name: 'science',
+ slug: 'science',
+ description: 'Bildung, Hochschule, Publikationen, ...',
+ },
+ ],
+ locationName: 'France',
+ location: {
+ name: 'Paris',
+ nameDE: 'Paris',
+ nameEN: 'Paris',
+ },
+ // myRole: 'usual',
+ }
+ investigativeJournalism = {
+ id: 'g0',
+ name: 'Investigative Journalism',
+ slug: 'investigative-journalism',
+ about: 'Investigative journalists share ideas and insights and can collaborate.',
+ description: `
English:
This group is hidden.
What is our group for? This group was created to allow investigative journalists to share and collaborate.
How does it work? Here you can internally share posts and comments about them.
Deutsch:
Diese Gruppe ist verborgen.
Wofür ist unsere Gruppe? Diese Gruppe wurde geschaffen, um investigativen Journalisten den Austausch und die Zusammenarbeit zu ermöglichen.
Wie funktioniert das? Hier könnt ihr euch intern über Beiträge und Kommentare zu ihnen austauschen.
`,
+ descriptionExcerpt:
+ '
English:
This group is hidden.
What is our group for? This group was created to allow investigative journalists to share and collaborate.
How does it work? Here you can internally share posts and comments about them.
Deutsch:
Diese Gruppe ist verborgen.
… ',
+ groupType: 'hidden',
+ actionRadius: 'global',
+ categories: [
+ {
+ id: 'cat6',
+ icon: 'balance-scale',
+ name: 'law',
+ slug: 'law',
+ description: 'Menschenrechte, Gesetze, Verordnungen',
+ },
+ {
+ id: 'cat12',
+ icon: 'politics',
+ name: 'politics',
+ slug: 'politics',
+ description: 'Demokratie, Mitbestimmung, Wahlen, Korruption, Parteien',
+ },
+ {
+ id: 'cat16',
+ icon: 'media',
+ name: 'it-and-media',
+ slug: 'it-and-media',
+ description:
+ 'Nachrichten, Manipulation, Datenschutz, Überwachung, Datenkraken, AI, Software, Apps',
+ },
+ ],
+ locationName: 'Hamburg, Germany',
+ location: {
+ name: 'Hamburg',
+ nameDE: 'Hamburg',
+ nameEN: 'Hamburg',
+ },
+ // myRole: 'usual',
+ }
+ peterLustig = {
+ id: 'u1',
+ name: 'Peter Lustig',
+ slug: 'peter-lustig',
+ role: 'user',
+ }
+ jennyRostock = {
+ id: 'u3',
+ name: 'Jenny Rostock',
+ slug: 'jenny-rostock',
+ role: 'user',
+ }
+ bobDerBaumeister = {
+ id: 'u2',
+ name: 'Bob der Baumeister',
+ slug: 'bob-der-baumeister',
+ role: 'user',
+ }
+ huey = {
+ id: 'u4',
+ name: 'Huey',
+ slug: 'huey',
+ role: 'user',
+ }
+ })
+
+ describe('mount', () => {
+ Wrapper = (data = () => {}) => {
+ return mount(GroupProfileSlug, {
+ mocks,
+ localVue,
+ data,
+ })
+ }
+
+ describe('given a puplic group – "yoga-practice"', () => {
+ describe('given a current user', () => {
+ describe('as group owner – "peter-lustig"', () => {
+ beforeEach(() => {
+ mocks.$store = {
+ getters: {
+ 'auth/user': peterLustig,
+ 'auth/isModerator': () => false,
+ },
+ }
+ wrapper = Wrapper(() => {
+ return {
+ Group: [
+ {
+ ...yogaPractice,
+ myRole: 'owner',
+ },
+ ],
+ GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
+ }
+ })
+ })
+
+ it('has group name – to verificate the group', () => {
+ expect(wrapper.text()).toContain('Yoga Practice')
+ })
+
+ it('has AvatarUploader', () => {
+ expect(wrapper.find('.avatar-uploader').exists()).toBe(true)
+ })
+
+ it('has ProfileAvatar', () => {
+ expect(wrapper.find('.profile-avatar').exists()).toBe(true)
+ })
+
+ it('has GroupContentMenu', () => {
+ expect(wrapper.find('.group-content-menu').exists()).toBe(true)
+ })
+
+ it('has group slug', () => {
+ // expect(wrapper.find('[data-test="ampersand"]').exists()).toBe(true)
+ expect(wrapper.text()).toContain('&yoga-practice')
+ })
+
+ describe('displays no(!) group location – because is "null"', () => {
+ it('has no(!) group location icon "map-marker"', () => {
+ expect(wrapper.find('[data-test="map-marker"]').exists()).toBe(false)
+ })
+ })
+
+ it('has group foundation', () => {
+ expect(wrapper.text()).toContain('group.foundation')
+ })
+
+ it('has members count', () => {
+ expect(wrapper.text()).toContain('group.membersCount')
+ })
+
+ it('has join/leave button disabled(!)', () => {
+ expect(wrapper.find('.join-leave-button').exists()).toBe(true)
+ expect(wrapper.find('.join-leave-button').attributes('disabled')).toBe('disabled')
+ })
+
+ it('has group role "owner"', () => {
+ expect(wrapper.text()).toContain('group.role')
+ expect(wrapper.text()).toContain('group.roles.owner')
+ })
+
+ it('has group type "public"', () => {
+ expect(wrapper.text()).toContain('group.type')
+ expect(wrapper.text()).toContain('group.types.public')
+ })
+
+ it('has group action radius "interplanetary"', () => {
+ expect(wrapper.text()).toContain('group.actionRadius')
+ expect(wrapper.text()).toContain('group.actionRadii.interplanetary')
+ })
+
+ it('has group categories "psyche", "body-and-excercise", "spirituality"', () => {
+ expect(wrapper.text()).toContain('group.categories')
+ expect(wrapper.text()).toContain('contribution.category.name.psyche')
+ expect(wrapper.text()).toContain('contribution.category.name.body-and-excercise')
+ expect(wrapper.text()).toContain('contribution.category.name.spirituality')
+ })
+
+ it('has no(!) group goal – because is "null"', () => {
+ expect(wrapper.text()).not.toContain('group.goal')
+ })
+
+ it('has ProfileList with members', () => {
+ const profileList = wrapper.find('.profile-list')
+ expect(profileList.exists()).toBe(true)
+ expect(profileList.text()).toContain('group.membersListTitle')
+ expect(profileList.text()).not.toContain(
+ 'group.membersListTitleNotAllowedSeeingGroupMembers',
+ )
+ expect(profileList.text()).toContain('Peter Lustig')
+ expect(profileList.text()).toContain('Jenny Rostock')
+ expect(profileList.text()).toContain('Bob der Baumeister')
+ expect(profileList.text()).toContain('Huey')
+ })
+
+ describe('displays description – here as well the functionallity', () => {
+ let groupDescriptionBaseCard
+
+ beforeEach(async () => {
+ groupDescriptionBaseCard = wrapper.find('.group-description')
+ })
+
+ it('has description BaseCard', () => {
+ expect(groupDescriptionBaseCard.exists()).toBe(true)
+ })
+
+ describe('displays descriptionExcerpt first', () => {
+ it('has descriptionExcerpt', () => {
+ expect(groupDescriptionBaseCard.text()).toContain(
+ `What Is yoga?Yoga is not just about practicing asanas. It's about how we do it.And practicing asanas doesn't have to be yoga, it can be more athletic than yogic.What makes practicing asanas yogic?The important thing is:Use the exercises …`,
+ )
+ })
+
+ it('has "show more" button', () => {
+ expect(wrapper.vm.isDescriptionCollapsed).toBe(true)
+ expect(groupDescriptionBaseCard.text()).toContain('comment.show.more')
+ })
+ })
+
+ describe('after "show more" click displays full description', () => {
+ beforeEach(async () => {
+ await groupDescriptionBaseCard.find('.collaps-button').trigger('click')
+ await wrapper.vm.$nextTick()
+ })
+
+ it('has full description', () => {
+ // test if end of full description is visible
+ expect(groupDescriptionBaseCard.text()).toContain(
+ `Use the exercises (consciously) for your personal development.`,
+ )
+ })
+
+ it('has "show less" button', () => {
+ expect(wrapper.vm.isDescriptionCollapsed).toBe(false)
+ expect(groupDescriptionBaseCard.text()).toContain('comment.show.less')
+ })
+ })
+ })
+
+ it('has profile post add button', () => {
+ expect(wrapper.find('.profile-post-add-button').exists()).toBe(true)
+ })
+
+ it('has empty post list', () => {
+ expect(wrapper.find('[data-test="icon-empty"]').exists()).toBe(true)
+ })
+ })
+
+ describe('as usual member – "jenny-rostock"', () => {
+ beforeEach(() => {
+ mocks.$store = {
+ getters: {
+ 'auth/user': jennyRostock,
+ 'auth/isModerator': () => false,
+ },
+ }
+ wrapper = Wrapper(() => {
+ return {
+ Group: [
+ {
+ ...yogaPractice,
+ myRole: 'usual',
+ },
+ ],
+ GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
+ }
+ })
+ })
+
+ it('has group name – to verificate the group', () => {
+ expect(wrapper.text()).toContain('Yoga Practice')
+ })
+
+ it('has not(!) AvatarUploader', () => {
+ expect(wrapper.find('.avatar-uploader').exists()).toBe(false)
+ })
+
+ it('has ProfileAvatar', () => {
+ expect(wrapper.find('.profile-avatar').exists()).toBe(true)
+ })
+
+ it('has not(!) GroupContentMenu', () => {
+ expect(wrapper.find('.group-content-menu').exists()).toBe(false)
+ })
+
+ it('has group slug', () => {
+ // expect(wrapper.find('[data-test="ampersand"]').exists()).toBe(true)
+ expect(wrapper.text()).toContain('&yoga-practice')
+ })
+
+ describe('displays no(!) group location – because is "null"', () => {
+ it('has no(!) group location icon "map-marker"', () => {
+ expect(wrapper.find('[data-test="map-marker"]').exists()).toBe(false)
+ })
+ })
+
+ it('has group foundation', () => {
+ expect(wrapper.text()).toContain('group.foundation')
+ })
+
+ it('has members count', () => {
+ expect(wrapper.text()).toContain('group.membersCount')
+ })
+
+ it('has join/leave button enabled', () => {
+ expect(wrapper.find('.join-leave-button').exists()).toBe(true)
+ expect(wrapper.find('.join-leave-button').attributes('disabled')).toBeFalsy()
+ })
+
+ it('has group role "usual"', () => {
+ expect(wrapper.text()).toContain('group.role')
+ expect(wrapper.text()).toContain('group.roles.usual')
+ })
+
+ it('has group type "public"', () => {
+ expect(wrapper.text()).toContain('group.type')
+ expect(wrapper.text()).toContain('group.types.public')
+ })
+
+ it('has group action radius "interplanetary"', () => {
+ expect(wrapper.text()).toContain('group.actionRadius')
+ expect(wrapper.text()).toContain('group.actionRadii.interplanetary')
+ })
+
+ it('has group categories "psyche", "body-and-excercise", "spirituality"', () => {
+ expect(wrapper.text()).toContain('group.categories')
+ expect(wrapper.text()).toContain('contribution.category.name.psyche')
+ expect(wrapper.text()).toContain('contribution.category.name.body-and-excercise')
+ expect(wrapper.text()).toContain('contribution.category.name.spirituality')
+ })
+
+ it('has no(!) group goal – because is "null"', () => {
+ expect(wrapper.text()).not.toContain('group.goal')
+ })
+
+ it('has ProfileList with members', () => {
+ const profileList = wrapper.find('.profile-list')
+ expect(profileList.exists()).toBe(true)
+ expect(profileList.text()).toContain('group.membersListTitle')
+ expect(profileList.text()).not.toContain(
+ 'group.membersListTitleNotAllowedSeeingGroupMembers',
+ )
+ expect(profileList.text()).toContain('Peter Lustig')
+ expect(profileList.text()).toContain('Jenny Rostock')
+ expect(profileList.text()).toContain('Bob der Baumeister')
+ expect(profileList.text()).toContain('Huey')
+ })
+
+ it('has description BaseCard', () => {
+ expect(wrapper.find('.group-description').exists()).toBe(true)
+ })
+
+ it('has profile post add button', () => {
+ expect(wrapper.find('.profile-post-add-button').exists()).toBe(true)
+ })
+
+ it('has empty post list', () => {
+ expect(wrapper.find('[data-test="icon-empty"]').exists()).toBe(true)
+ })
+ })
+
+ describe('as pending member – "bob-der-baumeister"', () => {
+ beforeEach(() => {
+ mocks.$store = {
+ getters: {
+ 'auth/user': bobDerBaumeister,
+ 'auth/isModerator': () => false,
+ },
+ }
+ wrapper = Wrapper(() => {
+ return {
+ Group: [
+ {
+ ...yogaPractice,
+ myRole: 'pending',
+ },
+ ],
+ GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
+ }
+ })
+ })
+
+ it('has group name – to verificate the group', () => {
+ expect(wrapper.text()).toContain('Yoga Practice')
+ })
+
+ it('has not(!) AvatarUploader', () => {
+ expect(wrapper.find('.avatar-uploader').exists()).toBe(false)
+ })
+
+ it('has ProfileAvatar', () => {
+ expect(wrapper.find('.profile-avatar').exists()).toBe(true)
+ })
+
+ it('has not(!) GroupContentMenu', () => {
+ expect(wrapper.find('.group-content-menu').exists()).toBe(false)
+ })
+
+ it('has group slug', () => {
+ // expect(wrapper.find('[data-test="ampersand"]').exists()).toBe(true)
+ expect(wrapper.text()).toContain('&yoga-practice')
+ })
+
+ describe('displays no(!) group location – because is "null"', () => {
+ it('has no(!) group location icon "map-marker"', () => {
+ expect(wrapper.find('[data-test="map-marker"]').exists()).toBe(false)
+ })
+ })
+
+ it('has group foundation', () => {
+ expect(wrapper.text()).toContain('group.foundation')
+ })
+
+ it('has members count', () => {
+ expect(wrapper.text()).toContain('group.membersCount')
+ })
+
+ it('has join/leave button enabled', () => {
+ expect(wrapper.find('.join-leave-button').exists()).toBe(true)
+ expect(wrapper.find('.join-leave-button').attributes('disabled')).toBeFalsy()
+ })
+
+ it('has group role "pending"', () => {
+ expect(wrapper.text()).toContain('group.role')
+ expect(wrapper.text()).toContain('group.roles.pending')
+ })
+
+ it('has group type "public"', () => {
+ expect(wrapper.text()).toContain('group.type')
+ expect(wrapper.text()).toContain('group.types.public')
+ })
+
+ it('has group action radius "interplanetary"', () => {
+ expect(wrapper.text()).toContain('group.actionRadius')
+ expect(wrapper.text()).toContain('group.actionRadii.interplanetary')
+ })
+
+ it('has group categories "psyche", "body-and-excercise", "spirituality"', () => {
+ expect(wrapper.text()).toContain('group.categories')
+ expect(wrapper.text()).toContain('contribution.category.name.psyche')
+ expect(wrapper.text()).toContain('contribution.category.name.body-and-excercise')
+ expect(wrapper.text()).toContain('contribution.category.name.spirituality')
+ })
+
+ it('has no(!) group goal – because is "null"', () => {
+ expect(wrapper.text()).not.toContain('group.goal')
+ })
+
+ it('has ProfileList with members', () => {
+ const profileList = wrapper.find('.profile-list')
+ expect(profileList.exists()).toBe(true)
+ expect(profileList.text()).toContain('group.membersListTitle')
+ expect(profileList.text()).not.toContain(
+ 'group.membersListTitleNotAllowedSeeingGroupMembers',
+ )
+ expect(profileList.text()).toContain('Peter Lustig')
+ expect(profileList.text()).toContain('Jenny Rostock')
+ expect(profileList.text()).toContain('Bob der Baumeister')
+ expect(profileList.text()).toContain('Huey')
+ })
+
+ it('has description BaseCard', () => {
+ expect(wrapper.find('.group-description').exists()).toBe(true)
+ })
+
+ it('has no(!) profile post add button', () => {
+ expect(wrapper.find('.profile-post-add-button').exists()).toBe(false)
+ })
+
+ it('has empty post list', () => {
+ expect(wrapper.find('[data-test="icon-empty"]').exists()).toBe(true)
+ })
+ })
+
+ describe('as none(!) member – "huey"', () => {
+ beforeEach(() => {
+ mocks.$store = {
+ getters: {
+ 'auth/user': huey,
+ 'auth/isModerator': () => false,
+ },
+ }
+ wrapper = Wrapper(() => {
+ return {
+ Group: [
+ {
+ ...yogaPractice,
+ myRole: null,
+ },
+ ],
+ GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
+ }
+ })
+ })
+
+ it('has group name – to verificate the group', () => {
+ expect(wrapper.text()).toContain('Yoga Practice')
+ })
+
+ it('has not(!) AvatarUploader', () => {
+ expect(wrapper.find('.avatar-uploader').exists()).toBe(false)
+ })
+
+ it('has ProfileAvatar', () => {
+ expect(wrapper.find('.profile-avatar').exists()).toBe(true)
+ })
+
+ it('has not(!) GroupContentMenu', () => {
+ expect(wrapper.find('.group-content-menu').exists()).toBe(false)
+ })
+
+ it('has group slug', () => {
+ // expect(wrapper.find('[data-test="ampersand"]').exists()).toBe(true)
+ expect(wrapper.text()).toContain('&yoga-practice')
+ })
+
+ describe('displays no(!) group location – because is "null"', () => {
+ it('has no(!) group location icon "map-marker"', () => {
+ expect(wrapper.find('[data-test="map-marker"]').exists()).toBe(false)
+ })
+ })
+
+ it('has group foundation', () => {
+ expect(wrapper.text()).toContain('group.foundation')
+ })
+
+ it('has members count', () => {
+ expect(wrapper.text()).toContain('group.membersCount')
+ })
+
+ it('has join/leave button enabled', () => {
+ expect(wrapper.find('.join-leave-button').exists()).toBe(true)
+ expect(wrapper.find('.join-leave-button').attributes('disabled')).toBeFalsy()
+ })
+
+ it('has no(!) group role', () => {
+ expect(wrapper.text()).not.toContain('group.role')
+ expect(wrapper.text()).not.toContain('group.roles')
+ })
+
+ it('has group type "public"', () => {
+ expect(wrapper.text()).toContain('group.type')
+ expect(wrapper.text()).toContain('group.types.public')
+ })
+
+ it('has group action radius "interplanetary"', () => {
+ expect(wrapper.text()).toContain('group.actionRadius')
+ expect(wrapper.text()).toContain('group.actionRadii.interplanetary')
+ })
+
+ it('has group categories "psyche", "body-and-excercise", "spirituality"', () => {
+ expect(wrapper.text()).toContain('group.categories')
+ expect(wrapper.text()).toContain('contribution.category.name.psyche')
+ expect(wrapper.text()).toContain('contribution.category.name.body-and-excercise')
+ expect(wrapper.text()).toContain('contribution.category.name.spirituality')
+ })
+
+ it('has no(!) group goal – because is "null"', () => {
+ expect(wrapper.text()).not.toContain('group.goal')
+ })
+
+ it('has ProfileList with members', () => {
+ const profileList = wrapper.find('.profile-list')
+ expect(profileList.exists()).toBe(true)
+ expect(profileList.text()).toContain('group.membersListTitle')
+ expect(profileList.text()).not.toContain(
+ 'group.membersListTitleNotAllowedSeeingGroupMembers',
+ )
+ expect(profileList.text()).toContain('Peter Lustig')
+ expect(profileList.text()).toContain('Jenny Rostock')
+ expect(profileList.text()).toContain('Bob der Baumeister')
+ expect(profileList.text()).toContain('Huey')
+ })
+
+ it('has description BaseCard', () => {
+ expect(wrapper.find('.group-description').exists()).toBe(true)
+ })
+
+ it('has no(!) profile post add button', () => {
+ expect(wrapper.find('.profile-post-add-button').exists()).toBe(false)
+ })
+
+ it('has empty post list', () => {
+ expect(wrapper.find('[data-test="icon-empty"]').exists()).toBe(true)
+ })
+ })
+ })
+ })
+
+ describe('given a closed group – "school-for-citizens"', () => {
+ describe('given a current user', () => {
+ describe('as group owner – "peter-lustig"', () => {
+ beforeEach(() => {
+ mocks.$store = {
+ getters: {
+ 'auth/user': peterLustig,
+ 'auth/isModerator': () => false,
+ },
+ }
+ wrapper = Wrapper(() => {
+ return {
+ Group: [
+ {
+ ...schoolForCitizens,
+ myRole: 'owner',
+ },
+ ],
+ GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
+ }
+ })
+ })
+
+ it('has group name – to verificate the group', () => {
+ expect(wrapper.text()).toContain('School For Citizens')
+ })
+
+ it('has AvatarUploader', () => {
+ expect(wrapper.find('.avatar-uploader').exists()).toBe(true)
+ })
+
+ it('has ProfileAvatar', () => {
+ expect(wrapper.find('.profile-avatar').exists()).toBe(true)
+ })
+
+ it('has GroupContentMenu', () => {
+ expect(wrapper.find('.group-content-menu').exists()).toBe(true)
+ })
+
+ it('has group slug', () => {
+ // expect(wrapper.find('[data-test="ampersand"]').exists()).toBe(true)
+ expect(wrapper.text()).toContain('&school-for-citizens')
+ })
+
+ describe('displays group location', () => {
+ it('has group location icon "map-marker"', () => {
+ expect(wrapper.find('[data-test="map-marker"]').exists()).toBe(true)
+ })
+
+ it('has group location name "Paris"', () => {
+ expect(wrapper.text()).toContain('Paris')
+ })
+ })
+
+ it('has group foundation', () => {
+ expect(wrapper.text()).toContain('group.foundation')
+ })
+
+ it('has members count', () => {
+ expect(wrapper.text()).toContain('group.membersCount')
+ })
+
+ it('has join/leave button disabled(!)', () => {
+ expect(wrapper.find('.join-leave-button').exists()).toBe(true)
+ expect(wrapper.find('.join-leave-button').attributes('disabled')).toBe('disabled')
+ })
+
+ it('has group role "owner"', () => {
+ expect(wrapper.text()).toContain('group.role')
+ expect(wrapper.text()).toContain('group.roles.owner')
+ })
+
+ it('has group type "closed"', () => {
+ expect(wrapper.text()).toContain('group.type')
+ expect(wrapper.text()).toContain('group.types.closed')
+ })
+
+ it('has group action radius "national"', () => {
+ expect(wrapper.text()).toContain('group.actionRadius')
+ expect(wrapper.text()).toContain('group.actionRadii.national')
+ })
+
+ it('has group categories "children", "science"', () => {
+ expect(wrapper.text()).toContain('group.categories')
+ expect(wrapper.text()).toContain('contribution.category.name.children')
+ expect(wrapper.text()).toContain('contribution.category.name.science')
+ })
+
+ it('has group goal', () => {
+ expect(wrapper.text()).toContain('group.goal')
+ expect(wrapper.text()).toContain('Our children shall receive education for life.')
+ })
+
+ it('has ProfileList with members', () => {
+ const profileList = wrapper.find('.profile-list')
+ expect(profileList.exists()).toBe(true)
+ expect(profileList.text()).toContain('group.membersListTitle')
+ expect(profileList.text()).not.toContain(
+ 'group.membersListTitleNotAllowedSeeingGroupMembers',
+ )
+ expect(profileList.text()).toContain('Peter Lustig')
+ expect(profileList.text()).toContain('Jenny Rostock')
+ expect(profileList.text()).toContain('Bob der Baumeister')
+ expect(profileList.text()).toContain('Huey')
+ })
+
+ it('has description BaseCard', () => {
+ expect(wrapper.find('.group-description').exists()).toBe(true)
+ })
+
+ it('has profile post add button', () => {
+ expect(wrapper.find('.profile-post-add-button').exists()).toBe(true)
+ })
+
+ it('has empty post list', () => {
+ expect(wrapper.find('[data-test="icon-empty"]').exists()).toBe(true)
+ })
+ })
+
+ describe('as usual member – "jenny-rostock"', () => {
+ beforeEach(() => {
+ mocks.$store = {
+ getters: {
+ 'auth/user': jennyRostock,
+ 'auth/isModerator': () => false,
+ },
+ }
+ wrapper = Wrapper(() => {
+ return {
+ Group: [
+ {
+ ...schoolForCitizens,
+ myRole: 'usual',
+ },
+ ],
+ GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
+ }
+ })
+ })
+
+ it('has group name – to verificate the group', () => {
+ expect(wrapper.text()).toContain('School For Citizens')
+ })
+
+ it('has not(!) AvatarUploader', () => {
+ expect(wrapper.find('.avatar-uploader').exists()).toBe(false)
+ })
+
+ it('has ProfileAvatar', () => {
+ expect(wrapper.find('.profile-avatar').exists()).toBe(true)
+ })
+
+ it('has not(!) GroupContentMenu', () => {
+ expect(wrapper.find('.group-content-menu').exists()).toBe(false)
+ })
+
+ it('has group slug', () => {
+ // expect(wrapper.find('[data-test="ampersand"]').exists()).toBe(true)
+ expect(wrapper.text()).toContain('&school-for-citizens')
+ })
+
+ describe('displays group location', () => {
+ it('has group location icon "map-marker"', () => {
+ expect(wrapper.find('[data-test="map-marker"]').exists()).toBe(true)
+ })
+
+ it('has group location name "Paris"', () => {
+ expect(wrapper.text()).toContain('Paris')
+ })
+ })
+
+ it('has group foundation', () => {
+ expect(wrapper.text()).toContain('group.foundation')
+ })
+
+ it('has members count', () => {
+ expect(wrapper.text()).toContain('group.membersCount')
+ })
+
+ it('has join/leave button enabled', () => {
+ expect(wrapper.find('.join-leave-button').exists()).toBe(true)
+ expect(wrapper.find('.join-leave-button').attributes('disabled')).toBeFalsy()
+ })
+
+ it('has group role "usual"', () => {
+ expect(wrapper.text()).toContain('group.role')
+ expect(wrapper.text()).toContain('group.roles.usual')
+ })
+
+ it('has group type "closed"', () => {
+ expect(wrapper.text()).toContain('group.type')
+ expect(wrapper.text()).toContain('group.types.closed')
+ })
+
+ it('has group action radius "national"', () => {
+ expect(wrapper.text()).toContain('group.actionRadius')
+ expect(wrapper.text()).toContain('group.actionRadii.national')
+ })
+
+ it('has group categories "children", "science"', () => {
+ expect(wrapper.text()).toContain('group.categories')
+ expect(wrapper.text()).toContain('contribution.category.name.children')
+ expect(wrapper.text()).toContain('contribution.category.name.science')
+ })
+
+ it('has group goal', () => {
+ expect(wrapper.text()).toContain('group.goal')
+ expect(wrapper.text()).toContain('Our children shall receive education for life.')
+ })
+
+ it('has ProfileList with members', () => {
+ const profileList = wrapper.find('.profile-list')
+ expect(profileList.exists()).toBe(true)
+ expect(profileList.text()).toContain('group.membersListTitle')
+ expect(profileList.text()).not.toContain(
+ 'group.membersListTitleNotAllowedSeeingGroupMembers',
+ )
+ expect(profileList.text()).toContain('Peter Lustig')
+ expect(profileList.text()).toContain('Jenny Rostock')
+ expect(profileList.text()).toContain('Bob der Baumeister')
+ expect(profileList.text()).toContain('Huey')
+ })
+
+ it('has description BaseCard', () => {
+ expect(wrapper.find('.group-description').exists()).toBe(true)
+ })
+
+ it('has profile post add button', () => {
+ expect(wrapper.find('.profile-post-add-button').exists()).toBe(true)
+ })
+
+ it('has empty post list', () => {
+ expect(wrapper.find('[data-test="icon-empty"]').exists()).toBe(true)
+ })
+ })
+
+ describe('as pending member – "bob-der-baumeister"', () => {
+ beforeEach(() => {
+ mocks.$store = {
+ getters: {
+ 'auth/user': bobDerBaumeister,
+ 'auth/isModerator': () => false,
+ },
+ }
+ wrapper = Wrapper(() => {
+ return {
+ Group: [
+ {
+ ...schoolForCitizens,
+ myRole: 'pending',
+ },
+ ],
+ GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
+ }
+ })
+ })
+
+ it('has group name – to verificate the group', () => {
+ expect(wrapper.text()).toContain('School For Citizens')
+ })
+
+ it('has not(!) AvatarUploader', () => {
+ expect(wrapper.find('.avatar-uploader').exists()).toBe(false)
+ })
+
+ it('has ProfileAvatar', () => {
+ expect(wrapper.find('.profile-avatar').exists()).toBe(true)
+ })
+
+ it('has not(!) GroupContentMenu', () => {
+ expect(wrapper.find('.group-content-menu').exists()).toBe(false)
+ })
+
+ it('has group slug', () => {
+ // expect(wrapper.find('[data-test="ampersand"]').exists()).toBe(true)
+ expect(wrapper.text()).toContain('&school-for-citizens')
+ })
+
+ describe('displays group location', () => {
+ it('has group location icon "map-marker"', () => {
+ expect(wrapper.find('[data-test="map-marker"]').exists()).toBe(true)
+ })
+
+ it('has group location name "Paris"', () => {
+ expect(wrapper.text()).toContain('Paris')
+ })
+ })
+
+ it('has group foundation', () => {
+ expect(wrapper.text()).toContain('group.foundation')
+ })
+
+ it('has no(!) members count', () => {
+ expect(wrapper.text()).not.toContain('group.membersCount')
+ })
+
+ it('has join/leave button enabled', () => {
+ expect(wrapper.find('.join-leave-button').exists()).toBe(true)
+ expect(wrapper.find('.join-leave-button').attributes('disabled')).toBeFalsy()
+ })
+
+ it('has group role "pending"', () => {
+ expect(wrapper.text()).toContain('group.role')
+ expect(wrapper.text()).toContain('group.roles.pending')
+ })
+
+ it('has group type "closed"', () => {
+ expect(wrapper.text()).toContain('group.type')
+ expect(wrapper.text()).toContain('group.types.closed')
+ })
+
+ it('has group action radius "national"', () => {
+ expect(wrapper.text()).toContain('group.actionRadius')
+ expect(wrapper.text()).toContain('group.actionRadii.national')
+ })
+
+ it('has group categories "children", "science"', () => {
+ expect(wrapper.text()).toContain('group.categories')
+ expect(wrapper.text()).toContain('contribution.category.name.children')
+ expect(wrapper.text()).toContain('contribution.category.name.science')
+ })
+
+ it('has group goal', () => {
+ expect(wrapper.text()).toContain('group.goal')
+ expect(wrapper.text()).toContain('Our children shall receive education for life.')
+ })
+
+ it('has ProfileList without(!) members', () => {
+ const profileList = wrapper.find('.profile-list')
+ expect(profileList.exists()).toBe(true)
+ // expect(profileList.text()).not.toContain('group.membersListTitle') // does not work, because is part of 'group.membersListTitleNotAllowedSeeingGroupMembers'
+ expect(profileList.text()).toContain(
+ 'group.membersListTitleNotAllowedSeeingGroupMembers',
+ )
+ expect(profileList.text()).not.toContain('Peter Lustig')
+ expect(profileList.text()).not.toContain('Jenny Rostock')
+ expect(profileList.text()).not.toContain('Bob der Baumeister')
+ expect(profileList.text()).not.toContain('Huey')
+ })
+
+ it('has description BaseCard', () => {
+ expect(wrapper.find('.group-description').exists()).toBe(true)
+ })
+
+ it('has no(!) profile post add button', () => {
+ expect(wrapper.find('.profile-post-add-button').exists()).toBe(false)
+ })
+
+ it('has empty post list', () => {
+ expect(wrapper.find('[data-test="icon-empty"]').exists()).toBe(true)
+ })
+ })
+
+ describe('as none(!) member – "huey"', () => {
+ beforeEach(() => {
+ mocks.$store = {
+ getters: {
+ 'auth/user': huey,
+ 'auth/isModerator': () => false,
+ },
+ }
+ wrapper = Wrapper(() => {
+ return {
+ Group: [
+ {
+ ...schoolForCitizens,
+ myRole: null,
+ },
+ ],
+ GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
+ }
+ })
+ })
+
+ it('has group name – to verificate the group', () => {
+ expect(wrapper.text()).toContain('School For Citizens')
+ })
+
+ it('has not(!) AvatarUploader', () => {
+ expect(wrapper.find('.avatar-uploader').exists()).toBe(false)
+ })
+
+ it('has ProfileAvatar', () => {
+ expect(wrapper.find('.profile-avatar').exists()).toBe(true)
+ })
+
+ it('has not(!) GroupContentMenu', () => {
+ expect(wrapper.find('.group-content-menu').exists()).toBe(false)
+ })
+
+ it('has group slug', () => {
+ // expect(wrapper.find('[data-test="ampersand"]').exists()).toBe(true)
+ expect(wrapper.text()).toContain('&school-for-citizens')
+ })
+
+ describe('displays group location', () => {
+ it('has group location icon "map-marker"', () => {
+ expect(wrapper.find('[data-test="map-marker"]').exists()).toBe(true)
+ })
+
+ it('has group location name "Paris"', () => {
+ expect(wrapper.text()).toContain('Paris')
+ })
+ })
+
+ it('has group foundation', () => {
+ expect(wrapper.text()).toContain('group.foundation')
+ })
+
+ it('has no(!) members count', () => {
+ expect(wrapper.text()).not.toContain('group.membersCount')
+ })
+
+ it('has join/leave button enabled', () => {
+ expect(wrapper.find('.join-leave-button').exists()).toBe(true)
+ expect(wrapper.find('.join-leave-button').attributes('disabled')).toBeFalsy()
+ })
+
+ it('has no(!) group role', () => {
+ expect(wrapper.text()).not.toContain('group.role')
+ expect(wrapper.text()).not.toContain('group.roles')
+ })
+
+ it('has group type "closed"', () => {
+ expect(wrapper.text()).toContain('group.type')
+ expect(wrapper.text()).toContain('group.types.closed')
+ })
+
+ it('has group action radius "national"', () => {
+ expect(wrapper.text()).toContain('group.actionRadius')
+ expect(wrapper.text()).toContain('group.actionRadii.national')
+ })
+
+ it('has group categories "children", "science"', () => {
+ expect(wrapper.text()).toContain('group.categories')
+ expect(wrapper.text()).toContain('contribution.category.name.children')
+ expect(wrapper.text()).toContain('contribution.category.name.science')
+ })
+
+ it('has group goal', () => {
+ expect(wrapper.text()).toContain('group.goal')
+ expect(wrapper.text()).toContain('Our children shall receive education for life.')
+ })
+
+ it('has ProfileList without(!) members', () => {
+ const profileList = wrapper.find('.profile-list')
+ expect(profileList.exists()).toBe(true)
+ // expect(profileList.text()).not.toContain('group.membersListTitle') // does not work, because is part of 'group.membersListTitleNotAllowedSeeingGroupMembers'
+ expect(profileList.text()).toContain(
+ 'group.membersListTitleNotAllowedSeeingGroupMembers',
+ )
+ expect(profileList.text()).not.toContain('Peter Lustig')
+ expect(profileList.text()).not.toContain('Jenny Rostock')
+ expect(profileList.text()).not.toContain('Bob der Baumeister')
+ expect(profileList.text()).not.toContain('Huey')
+ })
+
+ it('has description BaseCard', () => {
+ expect(wrapper.find('.group-description').exists()).toBe(true)
+ })
+
+ it('has no(!) profile post add button', () => {
+ expect(wrapper.find('.profile-post-add-button').exists()).toBe(false)
+ })
+
+ it('has empty post list', () => {
+ expect(wrapper.find('[data-test="icon-empty"]').exists()).toBe(true)
+ })
+ })
+ })
+ })
+
+ describe('given a hidden group – "investigative-journalism"', () => {
+ describe('given a current user', () => {
+ describe('as group owner – "peter-lustig"', () => {
+ beforeEach(() => {
+ mocks.$store = {
+ getters: {
+ 'auth/user': peterLustig,
+ 'auth/isModerator': () => false,
+ },
+ }
+ wrapper = Wrapper(() => {
+ return {
+ Group: [
+ {
+ ...investigativeJournalism,
+ myRole: 'owner',
+ },
+ ],
+ GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
+ }
+ })
+ })
+
+ it('has group name – to verificate the group', () => {
+ expect(wrapper.text()).toContain('Investigative Journalism')
+ })
+
+ it('has AvatarUploader', () => {
+ expect(wrapper.find('.avatar-uploader').exists()).toBe(true)
+ })
+
+ it('has ProfileAvatar', () => {
+ expect(wrapper.find('.profile-avatar').exists()).toBe(true)
+ })
+
+ it('has GroupContentMenu', () => {
+ expect(wrapper.find('.group-content-menu').exists()).toBe(true)
+ })
+
+ it('has group slug', () => {
+ // expect(wrapper.find('[data-test="ampersand"]').exists()).toBe(true)
+ expect(wrapper.text()).toContain('&investigative-journalism')
+ })
+
+ describe('displays group location', () => {
+ it('has group location icon "map-marker"', () => {
+ expect(wrapper.find('[data-test="map-marker"]').exists()).toBe(true)
+ })
+
+ it('has group location name "Hamburg"', () => {
+ expect(wrapper.text()).toContain('Hamburg')
+ })
+ })
+
+ it('has group foundation', () => {
+ expect(wrapper.text()).toContain('group.foundation')
+ })
+
+ it('has members count', () => {
+ expect(wrapper.text()).toContain('group.membersCount')
+ })
+
+ it('has join/leave button disabled(!)', () => {
+ expect(wrapper.find('.join-leave-button').exists()).toBe(true)
+ expect(wrapper.find('.join-leave-button').attributes('disabled')).toBe('disabled')
+ })
+
+ it('has group role "owner"', () => {
+ expect(wrapper.text()).toContain('group.role')
+ expect(wrapper.text()).toContain('group.roles.owner')
+ })
+
+ it('has group type "hidden"', () => {
+ expect(wrapper.text()).toContain('group.type')
+ expect(wrapper.text()).toContain('group.types.hidden')
+ })
+
+ it('has group action radius "global"', () => {
+ expect(wrapper.text()).toContain('group.actionRadius')
+ expect(wrapper.text()).toContain('group.actionRadii.global')
+ })
+
+ it('has group categories "law", "politics", "it-and-media"', () => {
+ expect(wrapper.text()).toContain('group.categories')
+ expect(wrapper.text()).toContain('contribution.category.name.law')
+ expect(wrapper.text()).toContain('contribution.category.name.politics')
+ expect(wrapper.text()).toContain('contribution.category.name.it-and-media')
+ })
+
+ it('has group goal', () => {
+ expect(wrapper.text()).toContain('group.goal')
+ expect(wrapper.text()).toContain(
+ 'Investigative journalists share ideas and insights and can collaborate.',
+ )
+ })
+
+ it('has ProfileList with members', () => {
+ const profileList = wrapper.find('.profile-list')
+ expect(profileList.exists()).toBe(true)
+ expect(profileList.text()).toContain('group.membersListTitle')
+ expect(profileList.text()).not.toContain(
+ 'group.membersListTitleNotAllowedSeeingGroupMembers',
+ )
+ expect(profileList.text()).toContain('Peter Lustig')
+ expect(profileList.text()).toContain('Jenny Rostock')
+ expect(profileList.text()).toContain('Bob der Baumeister')
+ expect(profileList.text()).toContain('Huey')
+ })
+
+ it('has description BaseCard', () => {
+ expect(wrapper.find('.group-description').exists()).toBe(true)
+ })
+
+ it('has profile post add button', () => {
+ expect(wrapper.find('.profile-post-add-button').exists()).toBe(true)
+ })
+
+ it('has empty post list', () => {
+ expect(wrapper.find('[data-test="icon-empty"]').exists()).toBe(true)
+ })
+ })
+
+ describe('as usual member – "jenny-rostock"', () => {
+ beforeEach(() => {
+ mocks.$store = {
+ getters: {
+ 'auth/user': jennyRostock,
+ 'auth/isModerator': () => false,
+ },
+ }
+ wrapper = Wrapper(() => {
+ return {
+ Group: [
+ {
+ ...investigativeJournalism,
+ myRole: 'usual',
+ },
+ ],
+ GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
+ }
+ })
+ })
+
+ it('has group name – to verificate the group', () => {
+ expect(wrapper.text()).toContain('Investigative Journalism')
+ })
+
+ it('has not(!) AvatarUploader', () => {
+ expect(wrapper.find('.avatar-uploader').exists()).toBe(false)
+ })
+
+ it('has ProfileAvatar', () => {
+ expect(wrapper.find('.profile-avatar').exists()).toBe(true)
+ })
+
+ it('has not(!) GroupContentMenu', () => {
+ expect(wrapper.find('.group-content-menu').exists()).toBe(false)
+ })
+
+ it('has group slug', () => {
+ // expect(wrapper.find('[data-test="ampersand"]').exists()).toBe(true)
+ expect(wrapper.text()).toContain('&investigative-journalism')
+ })
+
+ describe('displays group location', () => {
+ it('has group location icon "map-marker"', () => {
+ expect(wrapper.find('[data-test="map-marker"]').exists()).toBe(true)
+ })
+
+ it('has group location name "Hamburg"', () => {
+ expect(wrapper.text()).toContain('Hamburg')
+ })
+ })
+
+ it('has group foundation', () => {
+ expect(wrapper.text()).toContain('group.foundation')
+ })
+
+ it('has members count', () => {
+ expect(wrapper.text()).toContain('group.membersCount')
+ })
+
+ it('has join/leave button enabled', () => {
+ expect(wrapper.find('.join-leave-button').exists()).toBe(true)
+ expect(wrapper.find('.join-leave-button').attributes('disabled')).toBeFalsy()
+ })
+
+ it('has group role "usual"', () => {
+ expect(wrapper.text()).toContain('group.role')
+ expect(wrapper.text()).toContain('group.roles.usual')
+ })
+
+ it('has group type "hidden"', () => {
+ expect(wrapper.text()).toContain('group.type')
+ expect(wrapper.text()).toContain('group.types.hidden')
+ })
+
+ it('has group action radius "global"', () => {
+ expect(wrapper.text()).toContain('group.actionRadius')
+ expect(wrapper.text()).toContain('group.actionRadii.global')
+ })
+
+ it('has group categories "law", "politics", "it-and-media"', () => {
+ expect(wrapper.text()).toContain('group.categories')
+ expect(wrapper.text()).toContain('contribution.category.name.law')
+ expect(wrapper.text()).toContain('contribution.category.name.politics')
+ expect(wrapper.text()).toContain('contribution.category.name.it-and-media')
+ })
+
+ it('has group goal', () => {
+ expect(wrapper.text()).toContain('group.goal')
+ expect(wrapper.text()).toContain(
+ 'Investigative journalists share ideas and insights and can collaborate.',
+ )
+ })
+
+ it('has ProfileList with members', () => {
+ const profileList = wrapper.find('.profile-list')
+ expect(profileList.exists()).toBe(true)
+ expect(profileList.text()).toContain('group.membersListTitle')
+ expect(profileList.text()).not.toContain(
+ 'group.membersListTitleNotAllowedSeeingGroupMembers',
+ )
+ expect(profileList.text()).toContain('Peter Lustig')
+ expect(profileList.text()).toContain('Jenny Rostock')
+ expect(profileList.text()).toContain('Bob der Baumeister')
+ expect(profileList.text()).toContain('Huey')
+ })
+
+ it('has description BaseCard', () => {
+ expect(wrapper.find('.group-description').exists()).toBe(true)
+ })
+
+ it('has profile post add button', () => {
+ expect(wrapper.find('.profile-post-add-button').exists()).toBe(true)
+ })
+
+ it('has empty post list', () => {
+ expect(wrapper.find('[data-test="icon-empty"]').exists()).toBe(true)
+ })
+ })
+
+ describe('as pending member – "bob-der-baumeister"', () => {
+ beforeEach(() => {
+ mocks.$store = {
+ getters: {
+ 'auth/user': bobDerBaumeister,
+ 'auth/isModerator': () => false,
+ },
+ }
+ wrapper = Wrapper(() => {
+ return {
+ Group: [
+ {
+ ...investigativeJournalism,
+ myRole: 'pending',
+ },
+ ],
+ GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
+ }
+ })
+ })
+
+ it('has no(!) group name – to verificate the group', () => {
+ expect(wrapper.text()).not.toContain('Investigative Journalism')
+ })
+
+ it('has not(!) AvatarUploader', () => {
+ expect(wrapper.find('.avatar-uploader').exists()).toBe(false)
+ })
+
+ it('has not(!) ProfileAvatar', () => {
+ expect(wrapper.find('.profile-avatar').exists()).toBe(false)
+ })
+
+ it('has not(!) GroupContentMenu', () => {
+ expect(wrapper.find('.group-content-menu').exists()).toBe(false)
+ })
+
+ it('has no(!) group slug', () => {
+ // expect(wrapper.find('[data-test="ampersand"]').exists()).toBe(false)
+ expect(wrapper.text()).not.toContain('&investigative-journalism')
+ })
+
+ describe('displays not(!) group location', () => {
+ it('has no(!) group location icon "map-marker"', () => {
+ expect(wrapper.find('[data-test="map-marker"]').exists()).toBe(false)
+ })
+
+ it('has no(!) group location name "Hamburg"', () => {
+ expect(wrapper.text()).not.toContain('Hamburg')
+ })
+ })
+
+ it('has no(!) group foundation', () => {
+ expect(wrapper.text()).not.toContain('group.foundation')
+ })
+
+ it('has no(!) members count', () => {
+ expect(wrapper.text()).not.toContain('group.membersCount')
+ })
+
+ it('has no(!) join/leave button', () => {
+ expect(wrapper.find('.join-leave-button').exists()).toBe(false)
+ })
+
+ it('has no(!) group role', () => {
+ expect(wrapper.text()).not.toContain('group.role')
+ expect(wrapper.text()).not.toContain('group.roles')
+ })
+
+ it('has no(!) group type', () => {
+ expect(wrapper.text()).not.toContain('group.type')
+ expect(wrapper.text()).not.toContain('group.types')
+ })
+
+ it('has no(!) group action radius', () => {
+ expect(wrapper.text()).not.toContain('group.actionRadius')
+ expect(wrapper.text()).not.toContain('group.actionRadii')
+ })
+
+ it('has no(!) group categories "law", "politics", "it-and-media"', () => {
+ expect(wrapper.text()).not.toContain('group.categories')
+ expect(wrapper.text()).not.toContain('contribution.category.name.law')
+ expect(wrapper.text()).not.toContain('contribution.category.name.politics')
+ expect(wrapper.text()).not.toContain('contribution.category.name.it-and-media')
+ })
+
+ it('has no(!) group goal', () => {
+ expect(wrapper.text()).not.toContain('group.goal')
+ })
+
+ it('has not(!) ProfileList', () => {
+ const profileList = wrapper.find('.profile-list')
+ expect(profileList.exists()).toBe(false)
+ })
+
+ it('has not(!) description BaseCard', () => {
+ expect(wrapper.find('.group-description').exists()).toBe(false)
+ })
+
+ it('has no(!) profile post add button', () => {
+ expect(wrapper.find('.profile-post-add-button').exists()).toBe(false)
+ })
+
+ it('has no(!) empty post list', () => {
+ expect(wrapper.find('[data-test="icon-empty"]').exists()).toBe(false)
+ })
+ })
+
+ describe('as none(!) member – "huey"', () => {
+ beforeEach(() => {
+ mocks.$store = {
+ getters: {
+ 'auth/user': huey,
+ 'auth/isModerator': () => false,
+ },
+ }
+ wrapper = Wrapper(() => {
+ return {
+ Group: [
+ {
+ ...investigativeJournalism,
+ myRole: null,
+ },
+ ],
+ GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
+ }
+ })
+ })
+
+ it('has no(!) group name – to verificate the group', () => {
+ expect(wrapper.text()).not.toContain('Investigative Journalism')
+ })
+
+ it('has not(!) AvatarUploader', () => {
+ expect(wrapper.find('.avatar-uploader').exists()).toBe(false)
+ })
+
+ it('has not(!) ProfileAvatar', () => {
+ expect(wrapper.find('.profile-avatar').exists()).toBe(false)
+ })
+
+ it('has not(!) GroupContentMenu', () => {
+ expect(wrapper.find('.group-content-menu').exists()).toBe(false)
+ })
+
+ it('has no(!) group slug', () => {
+ // expect(wrapper.find('[data-test="ampersand"]').exists()).toBe(false)
+ expect(wrapper.text()).not.toContain('&investigative-journalism')
+ })
+
+ describe('displays not(!) group location', () => {
+ it('has no(!) group location icon "map-marker"', () => {
+ expect(wrapper.find('[data-test="map-marker"]').exists()).toBe(false)
+ })
+
+ it('has no(!) group location name "Hamburg"', () => {
+ expect(wrapper.text()).not.toContain('Hamburg')
+ })
+ })
+
+ it('has no(!) group foundation', () => {
+ expect(wrapper.text()).not.toContain('group.foundation')
+ })
+
+ it('has no(!) members count', () => {
+ expect(wrapper.text()).not.toContain('group.membersCount')
+ })
+
+ it('has no(!) join/leave button', () => {
+ expect(wrapper.find('.join-leave-button').exists()).toBe(false)
+ })
+
+ it('has no(!) group role', () => {
+ expect(wrapper.text()).not.toContain('group.role')
+ expect(wrapper.text()).not.toContain('group.roles')
+ })
+
+ it('has no(!) group type', () => {
+ expect(wrapper.text()).not.toContain('group.type')
+ expect(wrapper.text()).not.toContain('group.types')
+ })
+
+ it('has no(!) group action radius', () => {
+ expect(wrapper.text()).not.toContain('group.actionRadius')
+ expect(wrapper.text()).not.toContain('group.actionRadii')
+ })
+
+ it('has no(!) group categories "law", "politics", "it-and-media"', () => {
+ expect(wrapper.text()).not.toContain('group.categories')
+ expect(wrapper.text()).not.toContain('contribution.category.name.law')
+ expect(wrapper.text()).not.toContain('contribution.category.name.politics')
+ expect(wrapper.text()).not.toContain('contribution.category.name.it-and-media')
+ })
+
+ it('has no(!) group goal', () => {
+ expect(wrapper.text()).not.toContain('group.goal')
+ })
+
+ it('has not(!) ProfileList', () => {
+ const profileList = wrapper.find('.profile-list')
+ expect(profileList.exists()).toBe(false)
+ })
+
+ it('has not(!) description BaseCard', () => {
+ expect(wrapper.find('.group-description').exists()).toBe(false)
+ })
+
+ it('has no(!) profile post add button', () => {
+ expect(wrapper.find('.profile-post-add-button').exists()).toBe(false)
+ })
+
+ it('has no(!) empty post list', () => {
+ expect(wrapper.find('[data-test="icon-empty"]').exists()).toBe(false)
+ })
+ })
+ })
+ })
+ })
+})
diff --git a/webapp/pages/group/_id/_slug.vue b/webapp/pages/group/_id/_slug.vue
new file mode 100644
index 000000000..d1b410081
--- /dev/null
+++ b/webapp/pages/group/_id/_slug.vue
@@ -0,0 +1,677 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ groupName }}
+
+
+
+
+ {{ `&${groupSlug}` }}
+
+
+
+
+ {{ group && group.location ? group.location.name : '' }}
+
+
+
+ {{ $t('group.foundation') }} {{ group.createdAt | date('MMMM yyyy') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ $t('group.role') }}
+
+
+
+ {{ group && group.myRole ? $t('group.roles.' + group.myRole) : '' }}
+
+
+
+
+
+ {{ $t('group.type') }}
+
+
+
+ {{ group && group.groupType ? $t('group.types.' + group.groupType) : '' }}
+
+
+
+
+ {{ $t('group.actionRadius') }}
+
+
+
+ {{
+ group && group.actionRadius ? $t('group.actionRadii.' + group.actionRadius) : ''
+ }}
+
+
+
+
+
+
+
+
+
+ {{
+ $t(
+ 'group.categories',
+ {},
+ group && group.categories ? group.categories.length : 0,
+ )
+ }}
+
+
+
+
+
+
+
+
+
+
+ {{ $t('group.goal') }}
+
+
+
+ {{ group ? group.about : '' }}
+
+
+
+
+
+
+ {{ $t('profile.network.title') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ isDescriptionCollapsed ? $t('comment.show.more') : $t('comment.show.less') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/webapp/pages/group/create.vue b/webapp/pages/group/create.vue
new file mode 100644
index 000000000..ebdbbe37c
--- /dev/null
+++ b/webapp/pages/group/create.vue
@@ -0,0 +1,71 @@
+
+
+
+ {{ $t('group.createNewGroup.title') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/webapp/pages/group/edit/_id.vue b/webapp/pages/group/edit/_id.vue
new file mode 100644
index 000000000..7a0f9d051
--- /dev/null
+++ b/webapp/pages/group/edit/_id.vue
@@ -0,0 +1,66 @@
+
+
+
+ {{ $t('group.editGroupSettings.title') }}
+
+ {{ $t('group.editGroupSettings.groupName', { name: group.name }) }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/webapp/pages/group/edit/_id/index.vue b/webapp/pages/group/edit/_id/index.vue
new file mode 100644
index 000000000..e3c934dc5
--- /dev/null
+++ b/webapp/pages/group/edit/_id/index.vue
@@ -0,0 +1,72 @@
+
+
+
+ {{ $t('group.general') }}
+
+
+
+
+
+
+
diff --git a/webapp/pages/group/edit/_id/members.vue b/webapp/pages/group/edit/_id/members.vue
new file mode 100644
index 000000000..c1e19bcd1
--- /dev/null
+++ b/webapp/pages/group/edit/_id/members.vue
@@ -0,0 +1,57 @@
+
+
+
+ {{ $t('group.members') }}
+
+
+
+
+
+
+
diff --git a/webapp/pages/groups.spec.js b/webapp/pages/groups.spec.js
new file mode 100644
index 000000000..0fbacd6b3
--- /dev/null
+++ b/webapp/pages/groups.spec.js
@@ -0,0 +1,35 @@
+import { config, mount } from '@vue/test-utils'
+import groups from './groups.vue'
+
+const localVue = global.localVue
+
+config.stubs['nuxt-link'] = '
'
+config.stubs['client-only'] = '
'
+
+describe('groups', () => {
+ let wrapper
+ let mocks
+
+ beforeEach(() => {
+ mocks = {
+ $t: jest.fn(),
+ }
+ })
+
+ describe('mount', () => {
+ const Wrapper = () => {
+ return mount(groups, {
+ mocks,
+ localVue,
+ })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders', () => {
+ expect(wrapper.is('div')).toBe(true)
+ })
+ })
+})
diff --git a/webapp/pages/groups.vue b/webapp/pages/groups.vue
new file mode 100644
index 000000000..386905c5b
--- /dev/null
+++ b/webapp/pages/groups.vue
@@ -0,0 +1,192 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/webapp/pages/index.vue b/webapp/pages/index.vue
index 9fb20d53b..8b06341eb 100644
--- a/webapp/pages/index.vue
+++ b/webapp/pages/index.vue
@@ -38,7 +38,6 @@
v-tooltip="{
content: $t('contribution.newPost'),
placement: 'left',
- delay: { show: 500 },
}"
class="post-add-button"
icon="plus"
diff --git a/webapp/pages/post/_id.spec.js b/webapp/pages/post/_id.spec.js.old
similarity index 100%
rename from webapp/pages/post/_id.spec.js
rename to webapp/pages/post/_id.spec.js.old
diff --git a/webapp/pages/post/_id.vue b/webapp/pages/post/_id.vue
index 14cc65a4e..c50ccc303 100644
--- a/webapp/pages/post/_id.vue
+++ b/webapp/pages/post/_id.vue
@@ -1,16 +1,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
diff --git a/webapp/pages/post/_id/_slug/index.spec.js b/webapp/pages/post/_id/_slug/index.spec.js
index 4737386ef..2dd4522b2 100644
--- a/webapp/pages/post/_id/_slug/index.spec.js
+++ b/webapp/pages/post/_id/_slug/index.spec.js
@@ -56,6 +56,10 @@ describe('PostSlug', () => {
},
$route: {
hash: '',
+ params: {
+ slug: 'slug',
+ id: 'id',
+ },
},
// If you are mocking the router, then don't use VueRouter with localVue: https://vue-test-utils.vuejs.org/guides/using-with-vue-router.html
$router: {
diff --git a/webapp/pages/post/_id/_slug/index.vue b/webapp/pages/post/_id/_slug/index.vue
index ff5c9a498..f111a4a89 100644
--- a/webapp/pages/post/_id/_slug/index.vue
+++ b/webapp/pages/post/_id/_slug/index.vue
@@ -1,109 +1,129 @@
-
-
-
-
-
-
-
-
-
-
- {{ post.title }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+ {{ $t('post.viewPost.title') }}
+
+ {{ $t('post.viewPost.forGroup.title', { name: post.group.name }) }}
+
-
-
-
-
-
-
- {{ $t('settings.blocked-users.explanation.commenting-disabled') }}
-
- {{ $t('settings.blocked-users.explanation.commenting-explanation') }}
-
- {{ $t('site.faq') }}
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ post.title }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ $t('settings.blocked-users.explanation.commenting-disabled') }}
+
+ {{ $t('settings.blocked-users.explanation.commenting-explanation') }}
+
+ {{ $t('site.faq') }}
+
+
+
+
+
+
+
+
+
+
@@ -169,6 +189,31 @@ export default {
}, 50)
},
computed: {
+ routes() {
+ const { slug, id } = this.$route.params
+ return [
+ {
+ name: this.$t('common.post', null, 1),
+ path: `/post/${id}/${slug}`,
+ children: [
+ {
+ name: this.$t('common.comment', null, 2),
+ path: `/post/${id}/${slug}#comments`,
+ },
+ // TODO implement
+ /* {
+ name: this.$t('common.letsTalk'),
+ path: `/post/${id}/${slug}#lets-talk`
+ }, */
+ // TODO implement
+ /* {
+ name: this.$t('common.versus'),
+ path: `/post/${id}/${slug}#versus`
+ } */
+ ],
+ },
+ ]
+ },
menuModalsData() {
return postMenuModalsData(
// "this.post" may not always be defined at the beginning …
@@ -268,6 +313,11 @@ export default {
}