mirror of
https://github.com/IT4Change/Ocelot-Social.git
synced 2025-12-13 07:45:56 +00:00
Merge branch '5059-epic-groups' of github.com:Ocelot-Social-Community/Ocelot-Social into 5059-groups/5318-group-profile-second
This commit is contained in:
commit
b7d4d506e3
@ -17,6 +17,7 @@
|
||||
|
||||
<script>
|
||||
import CategoryQuery from '~/graphql/CategoryQuery'
|
||||
import { CATEGORIES_MAX } from '~/constants/categories.js'
|
||||
import xor from 'lodash/xor'
|
||||
|
||||
export default {
|
||||
@ -32,7 +33,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
categories: null,
|
||||
selectedMax: 3,
|
||||
selectedMax: CATEGORIES_MAX,
|
||||
selectedCategoryIds: this.existingCategoryIds,
|
||||
}
|
||||
},
|
||||
|
||||
64
webapp/components/Group/GroupCard.vue
Normal file
64
webapp/components/Group/GroupCard.vue
Normal file
@ -0,0 +1,64 @@
|
||||
<template>
|
||||
<div>
|
||||
<ds-container class="group-card">
|
||||
<ds-page-title heading="Groups"></ds-page-title>
|
||||
<ds-card v-for="item in items" :key="item.id" space="xx-small">
|
||||
<nuxt-link :to="`/group/${item.id}`">{{ item.name }}</nuxt-link>
|
||||
{{ item.categories ? item.categories.map((category) => category.name) : [] }}
|
||||
<div>{{ item }}</div>
|
||||
<ds-space>
|
||||
<base-button
|
||||
v-if="item.myRole === 'owner'"
|
||||
icon="trash"
|
||||
@click="deleteGroup(item)"
|
||||
></base-button>
|
||||
<base-button
|
||||
v-if="item.myRole === 'pending'"
|
||||
icon="question-circle"
|
||||
@click="removePending(item)"
|
||||
></base-button>
|
||||
<base-button
|
||||
v-if="item.myRole === 'owner'"
|
||||
icon="edit"
|
||||
@click="editGroup(item)"
|
||||
></base-button>
|
||||
<base-button
|
||||
v-if="item.myRole === 'usual'"
|
||||
icon="close"
|
||||
@click="unfollowGroup(item)"
|
||||
></base-button>
|
||||
<base-button
|
||||
v-if="item.myRole === null"
|
||||
icon="plus"
|
||||
@click="addMemeberToGroup(item)"
|
||||
></base-button>
|
||||
</ds-space>
|
||||
</ds-card>
|
||||
</ds-container>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'GroupList',
|
||||
props: {
|
||||
items: { type: Array, default: () => [] },
|
||||
},
|
||||
methods: {
|
||||
removePending() {
|
||||
alert('removePending group')
|
||||
},
|
||||
editGroup(item) {
|
||||
this.$router.push({ path: `/group/edit/${item.id}` })
|
||||
},
|
||||
deleteGroup() {
|
||||
alert('delete group')
|
||||
},
|
||||
unfollowGroup() {
|
||||
alert('unfollow group')
|
||||
},
|
||||
addMemeberToGroup() {
|
||||
alert('addMemeberToGroup group')
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
150
webapp/components/Group/GroupForm.vue
Normal file
150
webapp/components/Group/GroupForm.vue
Normal file
@ -0,0 +1,150 @@
|
||||
<template>
|
||||
<div>
|
||||
<ds-container>
|
||||
<ds-form
|
||||
class="group-form"
|
||||
ref="groupForm"
|
||||
v-model="formData"
|
||||
:schema="formSchema"
|
||||
@submit="submit"
|
||||
>
|
||||
<ds-input
|
||||
v-model="formData.name"
|
||||
label="Gruppenname"
|
||||
placeholder="Your name ..."
|
||||
></ds-input>
|
||||
|
||||
<ds-select
|
||||
icon="user"
|
||||
v-model="formData.groupType"
|
||||
label="Sichtbarkeit"
|
||||
:options="['public', 'closed', 'hidden']"
|
||||
placeholder="Status ..."
|
||||
></ds-select>
|
||||
|
||||
<ds-input v-model="formData.about" label="Kurzbeschreibung" rows="3"></ds-input>
|
||||
|
||||
<ds-input
|
||||
v-model="formData.description"
|
||||
label="Beschreibung"
|
||||
type="textarea"
|
||||
rows="3"
|
||||
></ds-input>
|
||||
|
||||
<ds-select
|
||||
icon="card"
|
||||
v-model="formData.actionRadius"
|
||||
label="Radius"
|
||||
:options="['regional', 'national', 'continental', 'global']"
|
||||
placeholder="Radius ..."
|
||||
></ds-select>
|
||||
<categories-select
|
||||
v-if="categoriesActive"
|
||||
model="categoryIds"
|
||||
:existingCategoryIds="formData.categoryIds"
|
||||
/>
|
||||
|
||||
<div>{{ formData }}</div>
|
||||
|
||||
<ds-space margin-top="large">
|
||||
<ds-button @click.prevent="reset()">Reset form</ds-button>
|
||||
<ds-button
|
||||
type="submit"
|
||||
@click.prevent="submit()"
|
||||
icon="save"
|
||||
:disabled="disabled"
|
||||
primary
|
||||
>
|
||||
{{ update ? $t('group.update') : $t('group.save') }}
|
||||
</ds-button>
|
||||
</ds-space>
|
||||
</ds-form>
|
||||
<ds-space centered v-show="!update">
|
||||
<nuxt-link to="/group/my-groups">zurück</nuxt-link>
|
||||
</ds-space>
|
||||
</ds-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CategoriesSelect from '~/components/CategoriesSelect/CategoriesSelect'
|
||||
import { CATEGORIES_MIN, CATEGORIES_MAX } from '~/constants/categories.js'
|
||||
import { NAME_LENGTH_MIN, NAME_LENGTH_MAX } from '~/constants/groups.js'
|
||||
|
||||
export default {
|
||||
name: 'GroupForm',
|
||||
components: {
|
||||
CategoriesSelect,
|
||||
},
|
||||
props: {
|
||||
update: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
group: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default: () => ({}),
|
||||
},
|
||||
},
|
||||
data() {
|
||||
const { name, groupType, about, description, actionRadius, categories } = this.group
|
||||
return {
|
||||
categoriesActive: this.$env.CATEGORIES_ACTIVE,
|
||||
disabled: false,
|
||||
formData: {
|
||||
name: name || '',
|
||||
groupType: groupType || '',
|
||||
about: about || '',
|
||||
description: description || '',
|
||||
actionRadius: actionRadius || '',
|
||||
categoryIds: categories ? categories.map((category) => category.id) : [],
|
||||
},
|
||||
formSchema: {
|
||||
name: { required: true, min: NAME_LENGTH_MIN, max: NAME_LENGTH_MAX },
|
||||
groupType: { required: true },
|
||||
about: { required: true },
|
||||
description: { required: true },
|
||||
actionRadius: { required: true },
|
||||
categoryIds: {
|
||||
type: 'array',
|
||||
required: this.categoriesActive,
|
||||
validator: (_, value = []) => {
|
||||
if (
|
||||
this.categoriesActive &&
|
||||
(value.length < CATEGORIES_MIN || value.length > CATEGORIES_MAX)
|
||||
) {
|
||||
return [new Error(this.$t('common.validations.categories'))]
|
||||
}
|
||||
return []
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
submit() {
|
||||
const { name, about, description, groupType, actionRadius, categoryIds } = this.formData
|
||||
const variables = {
|
||||
name,
|
||||
about,
|
||||
description,
|
||||
groupType,
|
||||
actionRadius,
|
||||
categoryIds,
|
||||
}
|
||||
this.update
|
||||
? this.$emit('updateGroup', {
|
||||
...variables,
|
||||
id: this.group.id,
|
||||
})
|
||||
: this.$emit('createGroup', variables)
|
||||
},
|
||||
reset() {
|
||||
alert('reset')
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
15
webapp/components/Group/GroupLink.vue
Normal file
15
webapp/components/Group/GroupLink.vue
Normal file
@ -0,0 +1,15 @@
|
||||
<template>
|
||||
<div>
|
||||
<div>
|
||||
<ds-space><h3>Link zur Gruppe</h3></ds-space>
|
||||
<ds-space>
|
||||
<ds-copy-field>Copy Link for Invite Member please!</ds-copy-field>
|
||||
</ds-space>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'GroupLink',
|
||||
}
|
||||
</script>
|
||||
56
webapp/components/Group/GroupMember.vue
Normal file
56
webapp/components/Group/GroupMember.vue
Normal file
@ -0,0 +1,56 @@
|
||||
<template>
|
||||
<div>
|
||||
<ds-space><h3>Members</h3></ds-space>
|
||||
<ds-table :data="GroupMembers" :fields="tableFields">
|
||||
<template slot="avatar">
|
||||
<ds-avatar online size="small" name="Hans Peter"></ds-avatar>
|
||||
</template>
|
||||
<template slot="loves" slot-scope="scope">
|
||||
{{ scope.row.name }} loves {{ scope.row.loves }}
|
||||
</template>
|
||||
<template slot="edit" slot-scope="scope">
|
||||
<ds-button size="small" @click="deleteRow(scope.row)">delete</ds-button>
|
||||
</template>
|
||||
</ds-table>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'GroupMember',
|
||||
data() {
|
||||
return {
|
||||
tableFields: ['avatar', 'name', 'type', 'loves', 'edit'],
|
||||
GroupMembers: [
|
||||
{
|
||||
name: 'Rengar',
|
||||
type: 'Jungler',
|
||||
loves: 'Hide and seek',
|
||||
},
|
||||
{
|
||||
name: 'Renekton',
|
||||
type: 'Toplaner',
|
||||
loves: 'Slice and dice',
|
||||
},
|
||||
{
|
||||
name: 'Twitch',
|
||||
type: 'ADC',
|
||||
loves: 'Spray and pray',
|
||||
},
|
||||
{
|
||||
name: 'Blitz',
|
||||
type: 'Support',
|
||||
loves: 'Hook you up',
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
deleteRow(row) {
|
||||
const index = this.tableData.indexOf(row)
|
||||
if (index > -1) {
|
||||
this.tableData.splice(index, 1)
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
27
webapp/components/Group/GroupTeaser.vue
Normal file
27
webapp/components/Group/GroupTeaser.vue
Normal file
@ -0,0 +1,27 @@
|
||||
<template>
|
||||
<div class="group-teaser">
|
||||
<ds-grid-item :row-span="2" column-span="fullWidth">
|
||||
<ds-space centered>
|
||||
<nuxt-link :to="{ name: 'group-create' }">
|
||||
<base-button
|
||||
v-tooltip="{
|
||||
content: $t('group.newGroup'),
|
||||
placement: 'left',
|
||||
delay: { show: 500 },
|
||||
}"
|
||||
:path="{ name: 'group-create' }"
|
||||
class="profile-post-add-button"
|
||||
icon="plus"
|
||||
circle
|
||||
filled
|
||||
/>
|
||||
</nuxt-link>
|
||||
</ds-space>
|
||||
</ds-grid-item>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'GroupTeaser',
|
||||
}
|
||||
</script>
|
||||
@ -1,2 +1,4 @@
|
||||
// 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
|
||||
|
||||
@ -374,6 +374,13 @@
|
||||
"follow": "Folgen",
|
||||
"following": "Folge Ich"
|
||||
},
|
||||
"group": {
|
||||
"group-created": "Die Gruppe wurde angelegt!",
|
||||
"group-updated": "Die Gruppendaten wurden geändert!",
|
||||
"newGroup": "Erstelle eine neue Gruppe",
|
||||
"save": "Neue Gruppe anlegen",
|
||||
"update": "Änderung speichern"
|
||||
},
|
||||
"hashtags-filter": {
|
||||
"clearSearch": "Suche löschen",
|
||||
"hashtag-search": "Suche nach #{hashtag}",
|
||||
@ -751,6 +758,7 @@
|
||||
"unmute": "Stummschaltung aufheben",
|
||||
"unmuted": "{name} ist nicht mehr stummgeschaltet"
|
||||
},
|
||||
"myGroups": "Meine Gruppen",
|
||||
"name": "Einstellungen",
|
||||
"notifications": {
|
||||
"name": "Benachrichtigungen",
|
||||
|
||||
@ -374,6 +374,13 @@
|
||||
"follow": "Follow",
|
||||
"following": "Following"
|
||||
},
|
||||
"group": {
|
||||
"group-created": "The group was created!",
|
||||
"group-updated": "The group data has been changed.",
|
||||
"newGroup": "Create a new Group",
|
||||
"save": "Create new group",
|
||||
"update": "Save change"
|
||||
},
|
||||
"hashtags-filter": {
|
||||
"clearSearch": "Clear search",
|
||||
"hashtag-search": "Searching for #{hashtag}",
|
||||
@ -751,6 +758,7 @@
|
||||
"unmute": "Unmute user",
|
||||
"unmuted": "{name} is unmuted again"
|
||||
},
|
||||
"myGroups": "My Groups",
|
||||
"name": "Settings",
|
||||
"notifications": {
|
||||
"name": "Notifications",
|
||||
|
||||
46
webapp/pages/group/create.vue
Normal file
46
webapp/pages/group/create.vue
Normal file
@ -0,0 +1,46 @@
|
||||
<template>
|
||||
<div>
|
||||
<h2>Create Groupe</h2>
|
||||
<ds-flex :width="{ base: '100%' }" gutter="base">
|
||||
<ds-flex-item :width="{ base: '100%', md: 5 }">
|
||||
<group-form @createGroup="createGroup" />
|
||||
</ds-flex-item>
|
||||
<ds-flex-item :width="{ base: '100%', md: 1 }"> </ds-flex-item>
|
||||
</ds-flex>
|
||||
<hr />
|
||||
<group-member />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import GroupForm from '~/components/Group/GroupForm'
|
||||
import GroupMember from '~/components/Group/GroupMember'
|
||||
import { createGroupMutation } from '~/graphql/groups.js'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GroupForm,
|
||||
GroupMember,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
createGroupData: {},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async createGroup(value) {
|
||||
const { name, about, description, groupType, actionRadius, categoryIds } = value
|
||||
const variables = { name, about, description, groupType, actionRadius, categoryIds }
|
||||
try {
|
||||
await this.$apollo.mutate({
|
||||
mutation: createGroupMutation,
|
||||
variables,
|
||||
})
|
||||
this.$toast.success(this.$t('group.group-created'))
|
||||
} catch (error) {
|
||||
this.$toast.error(error.message)
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
63
webapp/pages/group/edit/_id.vue
Normal file
63
webapp/pages/group/edit/_id.vue
Normal file
@ -0,0 +1,63 @@
|
||||
<template>
|
||||
<div>
|
||||
<ds-page-title heading="Group Setting"></ds-page-title>
|
||||
<ds-flex gutter="small">
|
||||
<ds-flex-item :width="{ base: '100%', md: '200px' }">
|
||||
<ds-menu :routes="routes" :is-exact="() => true" />
|
||||
</ds-flex-item>
|
||||
<ds-flex-item :width="{ base: '100%', md: 1 }">
|
||||
<transition name="slide-up" appear>
|
||||
<nuxt-child :group="group" />
|
||||
</transition>
|
||||
</ds-flex-item>
|
||||
</ds-flex>
|
||||
<ds-space centered>
|
||||
<nuxt-link to="/group/my-groups">zurück</nuxt-link>
|
||||
</ds-space>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { groupQuery } from '~/graphql/groups.js'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
computed: {
|
||||
...mapGetters({
|
||||
user: 'auth/user',
|
||||
}),
|
||||
routes() {
|
||||
return [
|
||||
{
|
||||
name: 'General',
|
||||
path: `/group/edit/${this.group.id}`,
|
||||
},
|
||||
{
|
||||
name: 'Members',
|
||||
path: `/group/edit/${this.group.id}/members`,
|
||||
},
|
||||
]
|
||||
},
|
||||
},
|
||||
async asyncData(context) {
|
||||
const {
|
||||
app,
|
||||
error,
|
||||
params: { id },
|
||||
} = context
|
||||
const client = app.apolloProvider.defaultClient
|
||||
const {
|
||||
data: {
|
||||
Group: [group],
|
||||
},
|
||||
} = await client.query({
|
||||
query: groupQuery,
|
||||
variables: { id },
|
||||
})
|
||||
if (group.myRole !== 'owner') {
|
||||
error({ statusCode: 403, message: 'NONONNNO' })
|
||||
}
|
||||
return { group }
|
||||
},
|
||||
}
|
||||
</script>
|
||||
40
webapp/pages/group/edit/_id/index.vue
Normal file
40
webapp/pages/group/edit/_id/index.vue
Normal file
@ -0,0 +1,40 @@
|
||||
<template>
|
||||
<div>
|
||||
<ds-container>
|
||||
<group-form :group="group" :update="true" @updateGroup="updateGroup" />
|
||||
</ds-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import GroupForm from '~/components/Group/GroupForm'
|
||||
import { updateGroupMutation } from '~/graphql/groups.js'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GroupForm,
|
||||
},
|
||||
props: {
|
||||
group: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default: () => ({}),
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async updateGroup(value) {
|
||||
const { id, name, about, description, groupType, actionRadius, categoryIds } = value
|
||||
const variables = { id, name, about, description, groupType, actionRadius, categoryIds }
|
||||
try {
|
||||
await this.$apollo.mutate({
|
||||
mutation: updateGroupMutation,
|
||||
variables,
|
||||
})
|
||||
this.$toast.success(this.$t('group.group-updated'))
|
||||
} catch (error) {
|
||||
this.$toast.error(error.message)
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
16
webapp/pages/group/edit/_id/members.vue
Normal file
16
webapp/pages/group/edit/_id/members.vue
Normal file
@ -0,0 +1,16 @@
|
||||
<template>
|
||||
<div>
|
||||
<ds-container>
|
||||
<group-member />
|
||||
</ds-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import GroupMember from '~/components/Group/GroupMember'
|
||||
export default {
|
||||
components: {
|
||||
GroupMember,
|
||||
},
|
||||
}
|
||||
</script>
|
||||
44
webapp/pages/my-groups.vue
Normal file
44
webapp/pages/my-groups.vue
Normal file
@ -0,0 +1,44 @@
|
||||
<template>
|
||||
<div>
|
||||
<div>my groups</div>
|
||||
<group-teaser />
|
||||
<br />
|
||||
<br />
|
||||
<group-card :items="responseGroupListQuery" />
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import GroupTeaser from '~/components/Group/GroupTeaser.vue'
|
||||
import GroupCard from '~/components/Group/GroupCard.vue'
|
||||
import { groupQuery } from '~/graphql/groups.js'
|
||||
|
||||
export default {
|
||||
name: 'MyGroups',
|
||||
components: {
|
||||
GroupTeaser,
|
||||
GroupCard,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
responseGroupListQuery: [],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async groupListQuery() {
|
||||
try {
|
||||
const response = await this.$apollo.query({
|
||||
query: groupQuery,
|
||||
})
|
||||
this.responseGroupListQuery = response.data.Group
|
||||
} catch (error) {
|
||||
this.responseGroupListQuery = []
|
||||
} finally {
|
||||
this.pending = false
|
||||
}
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.groupListQuery()
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@ -39,6 +39,10 @@ export default {
|
||||
name: this.$t('settings.social-media.name'),
|
||||
path: `/settings/my-social-media`,
|
||||
},
|
||||
{
|
||||
name: this.$t('settings.myGroups'),
|
||||
path: `/my-groups`,
|
||||
},
|
||||
{
|
||||
name: this.$t('settings.muted-users.name'),
|
||||
path: `/settings/muted-users`,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user