mirror of
https://github.com/IT4Change/Ocelot-Social.git
synced 2025-12-13 07:45:56 +00:00
Merge branch '5059-epic-groups' into search-groups
This commit is contained in:
commit
37babb5c7c
2
.github/ISSUE_TEMPLATE.md
vendored
2
.github/ISSUE_TEMPLATE.md
vendored
@ -1,3 +1,5 @@
|
||||
<!-- You can find the latest issue templates here https://github.com/ulfgebhardt/issue-templates -->
|
||||
|
||||
<!--
|
||||
Please take a look at the issue templates at https://github.com/Ocelot-Social-Community/Ocelot-Social/issues/new/choose
|
||||
before submitting a new issue. Following one of the issue templates will ensure maintainers can route your request efficiently.
|
||||
|
||||
11
.github/ISSUE_TEMPLATE/bug_report.md
vendored
11
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -1,11 +1,10 @@
|
||||
---
|
||||
name: "\U0001F41B Bug Report"
|
||||
about: Create a report to help us to improve.
|
||||
title: "\U0001F41B [Bug] XXX"
|
||||
name: 🐛 Bug report
|
||||
about: Create a report to help us improve
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
title: 🐛 [Bug]
|
||||
---
|
||||
<!-- You can find the latest issue templates here https://github.com/ulfgebhardt/issue-templates -->
|
||||
|
||||
## :bug: Bug Report
|
||||
## 🐛 Bugreport
|
||||
<!-- Describe your issue in detail. Include screenshots if needed. Give us as much information as possible. Use a clear and concise description of what the bug is.-->
|
||||
|
||||
11
.github/ISSUE_TEMPLATE/devops_ticket.md
vendored
11
.github/ISSUE_TEMPLATE/devops_ticket.md
vendored
@ -1,11 +1,10 @@
|
||||
---
|
||||
name: "\U0001F4A5 DevOps Ticket"
|
||||
about: Help us manage our deployed app.
|
||||
title: "\U0001F4A5 [DevOps] XXX"
|
||||
name: 💥 DevOps ticket
|
||||
about: Help us manage our deployed Software.
|
||||
labels: devops
|
||||
assignees: ''
|
||||
|
||||
title: 💥 [DevOps]
|
||||
---
|
||||
<!-- You can find the latest issue templates here https://github.com/ulfgebhardt/issue-templates -->
|
||||
|
||||
## 💥 DevOps Ticket
|
||||
## 💥 DevOps ticket
|
||||
<!-- Describe your issue in detail. Include screenshots if needed. Give us as much information as possible. Use a clear and concise description of what the problem is.-->
|
||||
|
||||
12
.github/ISSUE_TEMPLATE/epic.md
vendored
12
.github/ISSUE_TEMPLATE/epic.md
vendored
@ -1,15 +1,13 @@
|
||||
---
|
||||
name: "\U0001F31F Epic"
|
||||
about: Define a big development step.
|
||||
title: "\U0001F31F [EPIC] XXX"
|
||||
name: 🌟 Epic
|
||||
about: Define a big development Step
|
||||
labels: epic
|
||||
assignees: ''
|
||||
|
||||
title: 🌟 [EPIC]
|
||||
---
|
||||
<!-- You can find the latest issue templates here https://github.com/ulfgebhardt/issue-templates -->
|
||||
|
||||
<!-- THIS ISSUE-TYPE IS NOT FOR YOU! -->
|
||||
<!-- If you need an answer right away, visit the ocelot.social Discord:
|
||||
https://discord.gg/AJSX9DCSUA -->
|
||||
<!-- Proceed only if you know what you are doing - have a chat with Project's Team first -->
|
||||
|
||||
## 🌟 EPIC
|
||||
<!-- Describe your Epic in detail. Include screenshots and drawings -->
|
||||
|
||||
11
.github/ISSUE_TEMPLATE/feature_request.md
vendored
11
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@ -1,11 +1,10 @@
|
||||
---
|
||||
name: "\U0001F680 Feature Request"
|
||||
about: Suggest an idea for this project.
|
||||
title: "\U0001F680 [Feature] XXX"
|
||||
name: 🚀 Feature request
|
||||
about: Suggest an idea for this project
|
||||
labels: feature
|
||||
assignees: ''
|
||||
|
||||
title: 🚀 [Feature]
|
||||
---
|
||||
<!-- You can find the latest issue templates here https://github.com/ulfgebhardt/issue-templates -->
|
||||
|
||||
## :rocket: Feature Request
|
||||
## 🚀 Feature
|
||||
<!-- Give a short summary of the Feature. Use Screenshots if you want. -->
|
||||
|
||||
14
.github/ISSUE_TEMPLATE/question.md
vendored
14
.github/ISSUE_TEMPLATE/question.md
vendored
@ -1,15 +1,13 @@
|
||||
---
|
||||
name: "\U0001F4AC Question"
|
||||
about: If you need help understanding ocelot.social.
|
||||
title: "\U0001F4AC [Question] XXX"
|
||||
name: 💬 Question
|
||||
about: If you need help understanding our Software.
|
||||
labels: question
|
||||
assignees: ''
|
||||
|
||||
title: 💬 [Question]
|
||||
---
|
||||
<!-- You can find the latest issue templates here https://github.com/ulfgebhardt/issue-templates -->
|
||||
|
||||
<!-- Chat with ocelot.social team -->
|
||||
<!-- If you need an answer right away, visit the ocelot.social Discord:
|
||||
https://discord.gg/AJSX9DCSUA -->
|
||||
<!-- Question the project's team -->
|
||||
<!-- If you need an answer right away, consider to take other means of communication with the project's team -->
|
||||
|
||||
## 💬 Question
|
||||
<!-- Describe your Question in detail. Include screenshots and drawings if needed. -->
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
---
|
||||
name: "\U0001F527 Refactor"
|
||||
name: 🔧 Refactor ticket
|
||||
about: Help us improve our code by refactoring it.
|
||||
title: "\U0001F527 [Refactor] XXX"
|
||||
labels: refactor
|
||||
assignees: ''
|
||||
|
||||
title: 🔧 [Refactor]
|
||||
---
|
||||
<!-- You can find the latest issue templates here https://github.com/ulfgebhardt/issue-templates -->
|
||||
|
||||
## 🔧 Refactor
|
||||
## 🔧 Refactor ticket
|
||||
<!-- Describe your issue in detail. Include screenshots if needed. Give us as much information as possible. Use a clear and concise description of what the problem is.-->
|
||||
13
.github/ISSUE_TEMPLATE/release.md
vendored
Normal file
13
.github/ISSUE_TEMPLATE/release.md
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
---
|
||||
name: 🎂 Release
|
||||
about: Define a Release
|
||||
labels: release
|
||||
title: 🎂 [RELEASE]
|
||||
---
|
||||
<!-- You can find the latest issue templates here https://github.com/ulfgebhardt/issue-templates -->
|
||||
|
||||
<!-- THIS ISSUE-TYPE IS NOT FOR YOU! -->
|
||||
<!-- Proceed only if you know what you are doing - have a chat with Project's Team first -->
|
||||
|
||||
## 🎂 RELEASE
|
||||
<!-- Describe your Release in detail. Include screenshots and drawings -->
|
||||
14
.github/PULL_REQUEST_TEMPLATE.md
vendored
14
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -1,15 +1,15 @@
|
||||
## 🍰 Pull Request
|
||||
<!-- You can find the latest issue templates here https://github.com/ulfgebhardt/issue-templates -->
|
||||
|
||||
## 🍰 Pullrequest
|
||||
<!-- Describe the Pullrequest. Use Screenshots if possible. -->
|
||||
|
||||
XXX
|
||||
|
||||
### Issues
|
||||
<!-- Which Issues does this fix, which are related? -->
|
||||
|
||||
<!-- Which Issues does this fix, which are related?
|
||||
- fixes #XXX
|
||||
- relates #XXX
|
||||
-->
|
||||
- None
|
||||
|
||||
### Todo
|
||||
<!-- In case some parts are still missing, list them here. -->
|
||||
|
||||
- [ ] XXX list here …
|
||||
- [X] None
|
||||
|
||||
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@ -267,7 +267,7 @@ jobs:
|
||||
report_name: Coverage Webapp
|
||||
type: lcov
|
||||
result_path: ./coverage/lcov.info
|
||||
min_coverage: 65
|
||||
min_coverage: 64
|
||||
token: ${{ github.token }}
|
||||
|
||||
##############################################################################
|
||||
|
||||
@ -360,6 +360,33 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl']
|
||||
}),
|
||||
])
|
||||
|
||||
// post into group
|
||||
await Promise.all([
|
||||
mutate({
|
||||
mutation: createPostMutation(),
|
||||
variables: {
|
||||
id: 'p0-g0',
|
||||
groupId: 'g0',
|
||||
title: `What happend in Shanghai?`,
|
||||
content: 'A sack of rise dropped in Shanghai. Should we further investigate?',
|
||||
categoryIds: ['cat6'],
|
||||
},
|
||||
}),
|
||||
])
|
||||
authenticatedUser = await bobDerBaumeister.toJson()
|
||||
await Promise.all([
|
||||
mutate({
|
||||
mutation: createPostMutation(),
|
||||
variables: {
|
||||
id: 'p1-g0',
|
||||
groupId: 'g0',
|
||||
title: `The man on the moon`,
|
||||
content: 'We have to further investigate about the stories of a man living on the moon.',
|
||||
categoryIds: ['cat12', 'cat16'],
|
||||
},
|
||||
}),
|
||||
])
|
||||
|
||||
authenticatedUser = await jennyRostock.toJson()
|
||||
await Promise.all([
|
||||
mutate({
|
||||
@ -439,6 +466,32 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl']
|
||||
},
|
||||
}),
|
||||
])
|
||||
// post into group
|
||||
await Promise.all([
|
||||
mutate({
|
||||
mutation: createPostMutation(),
|
||||
variables: {
|
||||
id: 'p0-g1',
|
||||
groupId: 'g1',
|
||||
title: `Can we use ocelot for education?`,
|
||||
content: 'I like the concept of this school. Can we use our software in this?',
|
||||
categoryIds: ['cat8'],
|
||||
},
|
||||
}),
|
||||
])
|
||||
authenticatedUser = await peterLustig.toJson()
|
||||
await Promise.all([
|
||||
mutate({
|
||||
mutation: createPostMutation(),
|
||||
variables: {
|
||||
id: 'p1-g1',
|
||||
groupId: 'g1',
|
||||
title: `Can we push this idea out of France?`,
|
||||
content: 'This idea is too inportant to have the scope only on France.',
|
||||
categoryIds: ['cat14'],
|
||||
},
|
||||
}),
|
||||
])
|
||||
|
||||
authenticatedUser = await bobDerBaumeister.toJson()
|
||||
await Promise.all([
|
||||
@ -527,6 +580,20 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl']
|
||||
}),
|
||||
])
|
||||
|
||||
authenticatedUser = await louie.toJson()
|
||||
await Promise.all([
|
||||
mutate({
|
||||
mutation: createPostMutation(),
|
||||
variables: {
|
||||
id: 'p0-g2',
|
||||
groupId: 'g2',
|
||||
title: `I am a Noob`,
|
||||
content: 'I am new to Yoga and did not join this group so far.',
|
||||
categoryIds: ['cat4'],
|
||||
},
|
||||
}),
|
||||
])
|
||||
|
||||
// Create Posts
|
||||
|
||||
const [p0, p1, p3, p4, p5, p6, p9, p10, p11, p13, p14, p15] = await Promise.all([
|
||||
|
||||
@ -138,6 +138,7 @@ describe('ContributionForm.vue', () => {
|
||||
categoryIds: [],
|
||||
id: null,
|
||||
image: null,
|
||||
groupId: null,
|
||||
},
|
||||
}
|
||||
postTitleInput = wrapper.find('.ds-input')
|
||||
@ -260,6 +261,7 @@ describe('ContributionForm.vue', () => {
|
||||
content: propsData.contribution.content,
|
||||
categoryIds: [],
|
||||
id: propsData.contribution.id,
|
||||
groupId: null,
|
||||
image: {
|
||||
sensitive: false,
|
||||
},
|
||||
|
||||
@ -99,6 +99,10 @@ export default {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
groupId: {
|
||||
type: String,
|
||||
default: () => null,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
const { title, content, image, categories } = this.contribution
|
||||
@ -173,6 +177,7 @@ export default {
|
||||
categoryIds,
|
||||
id: this.contribution.id || null,
|
||||
image,
|
||||
groupId: this.groupId,
|
||||
},
|
||||
})
|
||||
.then(({ data }) => {
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
<div class="filter-menu-options">
|
||||
<h2 class="title">{{ $t('filter-menu.filter-by') }}</h2>
|
||||
<following-filter />
|
||||
<categories-filter v-if="categoriesActive" />
|
||||
</div>
|
||||
<div class="filter-menu-options">
|
||||
<h2 class="title">{{ $t('filter-menu.order-by') }}</h2>
|
||||
@ -28,12 +29,19 @@ import Dropdown from '~/components/Dropdown'
|
||||
import { mapGetters } from 'vuex'
|
||||
import FollowingFilter from './FollowingFilter'
|
||||
import OrderByFilter from './OrderByFilter'
|
||||
import CategoriesFilter from './CategoriesFilter'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Dropdown,
|
||||
FollowingFilter,
|
||||
OrderByFilter,
|
||||
CategoriesFilter,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
categoriesActive: this.$env.CATEGORIES_ACTIVE,
|
||||
}
|
||||
},
|
||||
props: {
|
||||
placement: { type: String },
|
||||
|
||||
@ -11,13 +11,13 @@
|
||||
<template #default="{ errors }">
|
||||
<!-- group Name -->
|
||||
<ds-input
|
||||
:label="$t('group.name')"
|
||||
name="name"
|
||||
:label="$t('group.name')"
|
||||
model="name"
|
||||
autofocus
|
||||
:placeholder="`${$t('group.name')} …`"
|
||||
/>
|
||||
<ds-chip size="base" :color="errors && errors.name && 'danger'">
|
||||
<ds-chip size="base" :color="errors && errors.name ? 'danger' : 'medium'">
|
||||
{{ `${formData.name.length} / ${formSchema.name.min}–${formSchema.name.max}` }}
|
||||
<base-icon v-if="errors && errors.name" name="warning" />
|
||||
</ds-chip>
|
||||
@ -42,6 +42,7 @@
|
||||
<select
|
||||
class="select ds-input appearance--auto"
|
||||
name="groupType"
|
||||
model="groupType"
|
||||
:value="formData.groupType"
|
||||
:disabled="update"
|
||||
@change="changeGroupType($event)"
|
||||
@ -52,7 +53,7 @@
|
||||
</select>
|
||||
<ds-chip
|
||||
size="base"
|
||||
:color="errors && errors.groupType && formData.groupType === '' && 'danger'"
|
||||
:color="errors && errors.groupType && formData.groupType === '' ? 'danger' : 'medium'"
|
||||
>
|
||||
{{ `${formData.groupType === '' ? 0 : 1} / 1` }}
|
||||
<base-icon
|
||||
@ -77,14 +78,14 @@
|
||||
{{ $t('group.description') }}
|
||||
</ds-text>
|
||||
<editor
|
||||
name="description"
|
||||
model="description"
|
||||
:users="null"
|
||||
:value="formData.description"
|
||||
:hashtags="null"
|
||||
model="description"
|
||||
name="description"
|
||||
@input="updateEditorDescription"
|
||||
/>
|
||||
<ds-chip size="base" :color="errors && errors.description && 'danger'">
|
||||
<ds-chip size="base" :color="errors && errors.description ? 'danger' : 'medium'">
|
||||
{{ `${descriptionLength} / ${formSchema.description.min}` }}
|
||||
<base-icon v-if="errors && errors.description" name="warning" />
|
||||
</ds-chip>
|
||||
@ -110,7 +111,9 @@
|
||||
</select>
|
||||
<ds-chip
|
||||
size="base"
|
||||
:color="errors && errors.actionRadius && formData.actionRadius === '' && 'danger'"
|
||||
:color="
|
||||
errors && errors.actionRadius && formData.actionRadius === '' ? 'danger' : 'medium'
|
||||
"
|
||||
>
|
||||
{{ `${formData.actionRadius === '' ? 0 : 1} / 1` }}
|
||||
<base-icon
|
||||
@ -122,7 +125,7 @@
|
||||
<!-- location -->
|
||||
<ds-select
|
||||
id="city"
|
||||
:label="$t('settings.data.labelCity')"
|
||||
:label="$t('settings.data.labelCity') + locationNameLabelAddOnOldName"
|
||||
v-model="formData.locationName"
|
||||
:options="cities"
|
||||
icon="map-marker"
|
||||
@ -132,11 +135,11 @@
|
||||
@input.native="handleCityInput"
|
||||
/>
|
||||
<base-button
|
||||
v-if="formData.locationName !== ''"
|
||||
v-if="formLocationName !== ''"
|
||||
icon="close"
|
||||
ghost
|
||||
size="small"
|
||||
style="position: relative; display: inline-block; right: -93%; top: -45px"
|
||||
style="position: relative; display: inline-block; right: -96%; top: -33px; width: 26px"
|
||||
@click="formData.locationName = ''"
|
||||
></base-button>
|
||||
|
||||
@ -152,7 +155,7 @@
|
||||
<ds-chip
|
||||
v-if="categoriesActive"
|
||||
size="base"
|
||||
:color="errors && errors.categoryIds && 'danger'"
|
||||
:color="errors && errors.categoryIds ? 'danger' : 'medium'"
|
||||
>
|
||||
{{ formData.categoryIds.length }} / 3
|
||||
<base-icon v-if="errors && errors.categoryIds" name="warning" />
|
||||
@ -163,7 +166,7 @@
|
||||
<nuxt-link to="/my-groups">
|
||||
<ds-button>{{ $t('actions.cancel') }}</ds-button>
|
||||
</nuxt-link>
|
||||
<ds-button type="submit" icon="save" primary :disabled="errors" fill>
|
||||
<ds-button type="submit" icon="save" primary :disabled="checkFormError(errors)" fill>
|
||||
{{ update ? $t('group.update') : $t('group.save') }}
|
||||
</ds-button>
|
||||
</ds-space>
|
||||
@ -219,6 +222,12 @@ export default {
|
||||
groupType: groupType || '',
|
||||
about: about || '',
|
||||
description: description || '',
|
||||
// from database 'locationName' comes as "string | null"
|
||||
// 'formData.locationName':
|
||||
// see 'created': tries to set it to a "requestGeoData" object and fills the menu if possible
|
||||
// if user selects one from menu we get a "requestGeoData" object here
|
||||
// "requestGeoData" object: "{ id: String, label: String, value: String }"
|
||||
// otherwise it's a string: empty or none empty
|
||||
locationName: locationName || '',
|
||||
actionRadius: actionRadius || '',
|
||||
categoryIds: categories ? categories.map((category) => category.id) : [],
|
||||
@ -257,12 +266,63 @@ export default {
|
||||
},
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
// set to "requestGeoData" object and fill select menu if possible
|
||||
this.formData.locationName =
|
||||
(await this.requestGeoData(this.formLocationName)) || this.formLocationName
|
||||
},
|
||||
computed: {
|
||||
formLocationName() {
|
||||
const isNestedValue =
|
||||
typeof this.formData.locationName === 'object' &&
|
||||
typeof this.formData.locationName.value === 'string'
|
||||
const isDirectString = typeof this.formData.locationName === 'string'
|
||||
return isNestedValue
|
||||
? this.formData.locationName.value
|
||||
: isDirectString
|
||||
? this.formData.locationName
|
||||
: ''
|
||||
},
|
||||
locationNameLabelAddOnOldName() {
|
||||
return this.formLocationName !== '' ? ' — ' + this.formLocationName : ''
|
||||
},
|
||||
descriptionLength() {
|
||||
return this.$filters.removeHtml(this.formData.description).length
|
||||
},
|
||||
sameLocation() {
|
||||
const dbLocationName = this.group.locationName || ''
|
||||
return dbLocationName === this.formLocationName
|
||||
},
|
||||
sameCategories() {
|
||||
if (this.group.categories.length !== this.formData.categoryIds.length) return false
|
||||
const groupCategories = []
|
||||
this.group.categories.forEach((categories) => {
|
||||
groupCategories.push(categories.id)
|
||||
const some = this.formData.categoryIds.some((item) => item === categories.id)
|
||||
if (!some) return false
|
||||
})
|
||||
|
||||
return true
|
||||
},
|
||||
disableButtonByUpdate() {
|
||||
if (!this.update) return true
|
||||
return (
|
||||
this.group.name === this.formData.name &&
|
||||
this.group.slug === this.formData.slug &&
|
||||
this.group.about === this.formData.about &&
|
||||
this.group.description === this.formData.description &&
|
||||
this.group.actionRadius === this.formData.actionRadius &&
|
||||
this.sameLocation &&
|
||||
this.sameCategories
|
||||
)
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
checkFormError(error) {
|
||||
if (!this.update && error && !!error && this.disableButtonByUpdate) return true
|
||||
if (this.update && !error && this.disableButtonByUpdate) return true
|
||||
return false
|
||||
},
|
||||
changeGroupType(event) {
|
||||
this.formData.groupType = event.target.value
|
||||
},
|
||||
@ -273,7 +333,7 @@ export default {
|
||||
this.$refs.groupForm.update('description', value)
|
||||
},
|
||||
submit() {
|
||||
const { name, about, description, groupType, actionRadius, locationName, categoryIds } =
|
||||
const { name, about, description, groupType, actionRadius, /* locationName, */ categoryIds } =
|
||||
this.formData
|
||||
const variables = {
|
||||
name,
|
||||
@ -281,7 +341,7 @@ export default {
|
||||
description,
|
||||
groupType,
|
||||
actionRadius,
|
||||
locationName: locationName.label ? locationName.label : '',
|
||||
locationName: this.formLocationName,
|
||||
categoryIds,
|
||||
}
|
||||
this.update
|
||||
@ -291,9 +351,12 @@ export default {
|
||||
})
|
||||
: this.$emit('createGroup', variables)
|
||||
},
|
||||
handleCityInput(value) {
|
||||
handleCityInput(event) {
|
||||
clearTimeout(timeout)
|
||||
timeout = setTimeout(() => this.requestGeoData(value), 500)
|
||||
timeout = setTimeout(
|
||||
() => this.requestGeoData(event.target ? event.target.value.trim() : ''),
|
||||
500,
|
||||
)
|
||||
},
|
||||
processLocationsResult(places) {
|
||||
if (!places.length) {
|
||||
@ -310,8 +373,7 @@ export default {
|
||||
|
||||
return result
|
||||
},
|
||||
async requestGeoData(e) {
|
||||
const value = e.target ? e.target.value.trim() : ''
|
||||
async requestGeoData(value) {
|
||||
if (value === '') {
|
||||
this.cities = []
|
||||
return
|
||||
@ -322,11 +384,13 @@ export default {
|
||||
const lang = this.$i18n.locale()
|
||||
|
||||
const {
|
||||
data: { queryLocations: res },
|
||||
data: { queryLocations: result },
|
||||
} = await this.$apollo.query({ query: queryLocations(), variables: { place, lang } })
|
||||
|
||||
this.cities = this.processLocationsResult(res)
|
||||
this.cities = this.processLocationsResult(result)
|
||||
this.loadingGeo = false
|
||||
|
||||
return this.cities.find((city) => city.value === value)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
33
webapp/components/Group/GroupList.spec.js
Normal file
33
webapp/components/Group/GroupList.spec.js
Normal file
@ -0,0 +1,33 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import GroupList from './GroupList.vue'
|
||||
|
||||
const localVue = global.localVue
|
||||
|
||||
const propsData = {
|
||||
groups: [],
|
||||
}
|
||||
|
||||
describe('GroupList', () => {
|
||||
let wrapper
|
||||
let mocks
|
||||
|
||||
beforeEach(() => {
|
||||
mocks = {
|
||||
$t: jest.fn(),
|
||||
}
|
||||
})
|
||||
|
||||
describe('mount', () => {
|
||||
const Wrapper = () => {
|
||||
return mount(GroupList, { propsData, mocks, localVue })
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = Wrapper()
|
||||
})
|
||||
|
||||
it('renders', () => {
|
||||
expect(wrapper.findAll('.group-list')).toHaveLength(1)
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="group-list">
|
||||
<ds-space margin-bottom="small" v-for="group in groups" :key="group.id">
|
||||
<group-teaser :group="group" />
|
||||
</ds-space>
|
||||
|
||||
34
webapp/components/Group/GroupMember.spec.js
Normal file
34
webapp/components/Group/GroupMember.spec.js
Normal file
@ -0,0 +1,34 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import GroupMember from './GroupMember.vue'
|
||||
|
||||
const localVue = global.localVue
|
||||
|
||||
const propsData = {
|
||||
groupId: '',
|
||||
groupMembers: [],
|
||||
}
|
||||
|
||||
describe('GroupMember', () => {
|
||||
let wrapper
|
||||
let mocks
|
||||
|
||||
beforeEach(() => {
|
||||
mocks = {
|
||||
$t: jest.fn(),
|
||||
}
|
||||
})
|
||||
|
||||
describe('mount', () => {
|
||||
const Wrapper = () => {
|
||||
return mount(GroupMember, { propsData, mocks, localVue })
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = Wrapper()
|
||||
})
|
||||
|
||||
it('renders', () => {
|
||||
expect(wrapper.findAll('.group-member')).toHaveLength(1)
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -1,5 +1,41 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="group-member">
|
||||
<base-card>
|
||||
<h2 class="title">{{ $t('group.addUser') }}</h2>
|
||||
<ds-form v-model="form" @submit="submit">
|
||||
<ds-flex gutter="small">
|
||||
<ds-flex-item width="90%">
|
||||
<ds-input
|
||||
name="query"
|
||||
model="query"
|
||||
:placeholder="$t('group.addUserPlaceholder')"
|
||||
icon="search"
|
||||
/>
|
||||
</ds-flex-item>
|
||||
<ds-flex-item width="30px">
|
||||
<!-- <base-button filled circle type="submit" icon="search" :loading="$apollo.loading" /> -->
|
||||
<base-button filled circle type="submit" icon="search" />
|
||||
</ds-flex-item>
|
||||
</ds-flex>
|
||||
</ds-form>
|
||||
<div v-if="noSlug">Kein User mit diesem Slug gefunden!</div>
|
||||
<div v-if="slugUser.length > 0">
|
||||
<ds-space margin="base" />
|
||||
<ds-flex>
|
||||
<ds-flex-item>
|
||||
<ds-avatar online size="small" :name="slugUser[0].name"></ds-avatar>
|
||||
</ds-flex-item>
|
||||
<ds-flex-item>{{ slugUser[0].name }}</ds-flex-item>
|
||||
<ds-flex-item>{{ slugUser[0].slug }}</ds-flex-item>
|
||||
<ds-flex-item>
|
||||
<ds-button size="small" primary @click="addMemberToGroup(slugUser)">
|
||||
{{ $t('group.addMemberToGroup') }}
|
||||
</ds-button>
|
||||
</ds-flex-item>
|
||||
</ds-flex>
|
||||
<ds-space margin="base" />
|
||||
</div>
|
||||
</base-card>
|
||||
<ds-table :fields="tableFields" :data="groupMembers" condensed>
|
||||
<template #avatar="scope">
|
||||
<nuxt-link
|
||||
@ -51,7 +87,12 @@
|
||||
</ds-chip>
|
||||
</template>
|
||||
<template #edit="scope">
|
||||
<ds-button size="small" primary :disabled="true" @click="openModal(scope.row)">
|
||||
<ds-button
|
||||
v-if="scope.row.myRoleInGroup !== 'owner'"
|
||||
size="small"
|
||||
primary
|
||||
@click="deleteMember(scope.row.id)"
|
||||
>
|
||||
<!-- TODO: implement removal of group members -->
|
||||
<!-- :disabled="scope.row.myRoleInGroup === 'owner'"
|
||||
-->
|
||||
@ -74,6 +115,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { minimisedUserQuery } from '~/graphql/User'
|
||||
import { changeGroupMemberRoleMutation } from '~/graphql/groups.js'
|
||||
|
||||
export default {
|
||||
@ -92,6 +134,11 @@ export default {
|
||||
return {
|
||||
isOpen: false,
|
||||
memberId: null,
|
||||
noSlug: false,
|
||||
slugUser: [],
|
||||
form: {
|
||||
query: '',
|
||||
},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -135,14 +182,53 @@ export default {
|
||||
this.$toast.error(error.message)
|
||||
}
|
||||
},
|
||||
async addMemberToGroup() {
|
||||
const newRole = 'usual'
|
||||
try {
|
||||
await this.$apollo.mutate({
|
||||
mutation: changeGroupMemberRoleMutation(),
|
||||
variables: { groupId: this.groupId, userId: this.slugUser[0].id, roleInGroup: newRole },
|
||||
})
|
||||
// this.$apollo.queries.GroupMembers.refetch()
|
||||
this.$emit('loadGroupMembers')
|
||||
this.slugUser = []
|
||||
this.form.query = ''
|
||||
this.$toast.success(
|
||||
this.$t('group.changeMemberRole', { role: this.$t(`group.roles.${newRole}`) }),
|
||||
)
|
||||
} catch (error) {
|
||||
this.$toast.error(error.message)
|
||||
}
|
||||
},
|
||||
async submit() {
|
||||
try {
|
||||
const {
|
||||
data: { User },
|
||||
} = await this.$apollo.query({
|
||||
query: minimisedUserQuery(),
|
||||
variables: {
|
||||
slug: this.form.query,
|
||||
},
|
||||
})
|
||||
if (User.length === 0) {
|
||||
this.noSlug = true
|
||||
} else {
|
||||
this.noSlug = false
|
||||
this.slugUser = User
|
||||
}
|
||||
} catch (error) {
|
||||
this.noSlug = true
|
||||
} finally {
|
||||
}
|
||||
},
|
||||
// TODO: implement removal of group members
|
||||
// openModal(row) {
|
||||
// this.isOpen = true
|
||||
// this.memberId = row.id
|
||||
// },
|
||||
// deleteMember(id) {
|
||||
// alert('deleteMember: ' + id)
|
||||
// },
|
||||
deleteMember(id) {
|
||||
alert('deleteMember: ' + id)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -1,13 +1,12 @@
|
||||
export default {
|
||||
MENU: [
|
||||
// {
|
||||
// name: 'Beiträge',
|
||||
// path: '/#',
|
||||
// nameIdent: 'ocelotRebranding.newsFeed',
|
||||
// path: '/',
|
||||
// },
|
||||
// {
|
||||
// name: 'Über Yunite',
|
||||
// path: '/#',
|
||||
// url: 'https://yunite.org',
|
||||
// nameIdent: 'ocelotRebranding.about',
|
||||
// url: 'https://ocelot.org',
|
||||
// },
|
||||
],
|
||||
}
|
||||
|
||||
@ -3,6 +3,15 @@
|
||||
export default {
|
||||
LOGO_HEADER_PATH: '/img/custom/logo-horizontal.svg',
|
||||
LOGO_HEADER_WIDTH: '130px',
|
||||
LOGO_HEADER_CLICK: {
|
||||
externalLink: null,
|
||||
internalPath: {
|
||||
to: {
|
||||
name: 'index',
|
||||
},
|
||||
scrollTo: '.main-navigation',
|
||||
},
|
||||
},
|
||||
LOGO_SIGNUP_PATH: '/img/custom/logo-squared.svg',
|
||||
LOGO_WELCOME_PATH: '/img/custom/logo-squared.svg',
|
||||
LOGO_LOGOUT_PATH: '/img/custom/logo-squared.svg',
|
||||
|
||||
@ -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
|
||||
|
||||
@ -39,6 +39,11 @@ export default (i18n) => {
|
||||
...locationAndBadges
|
||||
}
|
||||
}
|
||||
group {
|
||||
id
|
||||
name
|
||||
slug
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
@ -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
|
||||
|
||||
@ -5,7 +5,17 @@
|
||||
<div>
|
||||
<ds-flex class="main-navigation-flex">
|
||||
<ds-flex-item :width="{ base: LOGOS.LOGO_HEADER_WIDTH }" style="margin-right: 20px">
|
||||
<nuxt-link :to="{ name: 'index' }" v-scroll-to="'.main-navigation'">
|
||||
<a
|
||||
v-if="LOGOS.LOGO_HEADER_CLICK.externalLink"
|
||||
:href="LOGOS.LOGO_HEADER_CLICK.externalLink"
|
||||
>
|
||||
<logo logoType="header" />
|
||||
</a>
|
||||
<nuxt-link
|
||||
v-else
|
||||
:to="LOGOS.LOGO_HEADER_CLICK.internalPath.to"
|
||||
v-scroll-to="LOGOS.LOGO_HEADER_CLICK.internalPath.scrollTo"
|
||||
>
|
||||
<logo logoType="header" />
|
||||
</nuxt-link>
|
||||
</ds-flex-item>
|
||||
@ -19,24 +29,15 @@
|
||||
>
|
||||
<a v-if="item.url" :href="item.url" target="_blank">
|
||||
<ds-text size="large" bold>
|
||||
{{ item.name }}
|
||||
{{ $t(item.nameIdent) }}
|
||||
</ds-text>
|
||||
</a>
|
||||
<nuxt-link v-else :to="item.path">
|
||||
<ds-text size="large" bold>
|
||||
{{ item.name }}
|
||||
{{ $t(item.nameIdent) }}
|
||||
</ds-text>
|
||||
</nuxt-link>
|
||||
</ds-flex-item>
|
||||
<ds-flex-item
|
||||
v-if="categoriesActive && isLoggedIn"
|
||||
:class="{ 'hide-mobile-menu': !toggleMobileMenu }"
|
||||
style="flex-grow: 0; flex-basis: auto; margin-right: 20px"
|
||||
>
|
||||
<client-only>
|
||||
<categories-menu></categories-menu>
|
||||
</client-only>
|
||||
</ds-flex-item>
|
||||
<ds-flex-item
|
||||
:width="{ base: '40%', sm: '40%', md: '40%', lg: '0%' }"
|
||||
class="mobile-hamburger-menu"
|
||||
@ -116,35 +117,33 @@
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
import Logo from '~/components/Logo/Logo'
|
||||
import { SHOW_GROUP_BUTTON_IN_HEADER } from '~/constants/groups.js'
|
||||
import headerMenu from '~/constants/headerMenu.js'
|
||||
import LOGOS from '~/constants/logos.js'
|
||||
import LOGOS from '../constants/logos.js'
|
||||
import headerMenu from '../constants/headerMenu.js'
|
||||
import seo from '~/mixins/seo'
|
||||
import AvatarMenu from '~/components/AvatarMenu/AvatarMenu'
|
||||
import FilterMenu from '~/components/FilterMenu/FilterMenu.vue'
|
||||
import InviteButton from '~/components/InviteButton/InviteButton'
|
||||
import LocaleSwitch from '~/components/LocaleSwitch/LocaleSwitch'
|
||||
import Logo from '~/components/Logo/Logo'
|
||||
import SearchField from '~/components/features/SearchField/SearchField.vue'
|
||||
import Modal from '~/components/Modal'
|
||||
import AvatarMenu from '~/components/AvatarMenu/AvatarMenu'
|
||||
import CategoriesMenu from '~/components/FilterMenu/CategoriesMenu'
|
||||
import FilterMenu from '~/components/FilterMenu/FilterMenu.vue'
|
||||
import GroupButton from '~/components/Group/GroupButton'
|
||||
import InviteButton from '~/components/InviteButton/InviteButton'
|
||||
import NotificationMenu from '~/components/NotificationMenu/NotificationMenu'
|
||||
import PageFooter from '~/components/PageFooter/PageFooter'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Logo,
|
||||
LocaleSwitch,
|
||||
SearchField,
|
||||
Modal,
|
||||
NotificationMenu,
|
||||
AvatarMenu,
|
||||
FilterMenu,
|
||||
PageFooter,
|
||||
InviteButton,
|
||||
CategoriesMenu,
|
||||
LocaleSwitch,
|
||||
Logo,
|
||||
Modal,
|
||||
NotificationMenu,
|
||||
PageFooter,
|
||||
GroupButton,
|
||||
SearchField,
|
||||
},
|
||||
mixins: [seo],
|
||||
data() {
|
||||
|
||||
@ -404,6 +404,9 @@
|
||||
"regional": "Regionale Gruppe"
|
||||
},
|
||||
"actionRadius": "Aktionsradius",
|
||||
"addMemberToGroup": "Zur Gruppe hinzufügen",
|
||||
"addUser": "Benutzer hinzufügen",
|
||||
"addUserPlaceholder": "eindeutiger Benutzername > @slug-from-user",
|
||||
"categories": "Thema ::: Themen",
|
||||
"changeMemberRole": "Die Rolle wurde auf „{role}“ geändert!",
|
||||
"contentMenu": {
|
||||
@ -605,7 +608,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",
|
||||
@ -618,6 +633,12 @@
|
||||
"pinned": "Meldung",
|
||||
"takeAction": {
|
||||
"name": "Aktiv werden"
|
||||
},
|
||||
"viewPost": {
|
||||
"forGroup": {
|
||||
"title": "In der Gruppe „{name}“"
|
||||
},
|
||||
"title": "Beitrag"
|
||||
}
|
||||
},
|
||||
"profile": {
|
||||
|
||||
@ -404,6 +404,9 @@
|
||||
"regional": "Regional Group"
|
||||
},
|
||||
"actionRadius": "Action radius",
|
||||
"addMemberToGroup": "Add to group",
|
||||
"addUser": "Add User",
|
||||
"addUserPlaceholder": "unique username > @slug-from-user",
|
||||
"categories": "Topic ::: Topics",
|
||||
"changeMemberRole": "The role has been changed to “{role}”!",
|
||||
"contentMenu": {
|
||||
@ -605,7 +608,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",
|
||||
@ -618,6 +633,12 @@
|
||||
"pinned": "Announcement",
|
||||
"takeAction": {
|
||||
"name": "Take action"
|
||||
},
|
||||
"viewPost": {
|
||||
"forGroup": {
|
||||
"title": "In The Group “{name}”"
|
||||
},
|
||||
"title": "Post"
|
||||
}
|
||||
},
|
||||
"profile": {
|
||||
|
||||
@ -8,8 +8,8 @@ localVue.filter('date', (d) => d)
|
||||
config.stubs['client-only'] = '<span><slot /></span>'
|
||||
config.stubs['v-popover'] = '<span><slot /></span>'
|
||||
config.stubs['nuxt-link'] = '<span><slot /></span>'
|
||||
// config.stubs['infinite-loading'] = '<span><slot /></span>'
|
||||
// config.stubs['follow-list'] = '<span><slot /></span>'
|
||||
config.stubs['infinite-loading'] = '<span><slot /></span>'
|
||||
config.stubs['follow-list'] = '<span><slot /></span>'
|
||||
|
||||
describe('GroupProfileSlug', () => {
|
||||
let wrapper
|
||||
@ -196,10 +196,11 @@ describe('GroupProfileSlug', () => {
|
||||
})
|
||||
|
||||
describe('mount', () => {
|
||||
Wrapper = () => {
|
||||
Wrapper = (data = () => {}) => {
|
||||
return mount(GroupProfileSlug, {
|
||||
mocks,
|
||||
localVue,
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
@ -213,15 +214,16 @@ describe('GroupProfileSlug', () => {
|
||||
'auth/isModerator': () => false,
|
||||
},
|
||||
}
|
||||
wrapper = Wrapper()
|
||||
wrapper.setData({
|
||||
Group: [
|
||||
{
|
||||
...yogaPractice,
|
||||
myRole: 'owner',
|
||||
},
|
||||
],
|
||||
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
|
||||
wrapper = Wrapper(() => {
|
||||
return {
|
||||
Group: [
|
||||
{
|
||||
...yogaPractice,
|
||||
myRole: 'owner',
|
||||
},
|
||||
],
|
||||
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@ -365,15 +367,16 @@ describe('GroupProfileSlug', () => {
|
||||
'auth/isModerator': () => false,
|
||||
},
|
||||
}
|
||||
wrapper = Wrapper()
|
||||
wrapper.setData({
|
||||
Group: [
|
||||
{
|
||||
...yogaPractice,
|
||||
myRole: 'usual',
|
||||
},
|
||||
],
|
||||
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
|
||||
wrapper = Wrapper(() => {
|
||||
return {
|
||||
Group: [
|
||||
{
|
||||
...yogaPractice,
|
||||
myRole: 'usual',
|
||||
},
|
||||
],
|
||||
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@ -477,15 +480,16 @@ describe('GroupProfileSlug', () => {
|
||||
'auth/isModerator': () => false,
|
||||
},
|
||||
}
|
||||
wrapper = Wrapper()
|
||||
wrapper.setData({
|
||||
Group: [
|
||||
{
|
||||
...yogaPractice,
|
||||
myRole: 'pending',
|
||||
},
|
||||
],
|
||||
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
|
||||
wrapper = Wrapper(() => {
|
||||
return {
|
||||
Group: [
|
||||
{
|
||||
...yogaPractice,
|
||||
myRole: 'pending',
|
||||
},
|
||||
],
|
||||
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@ -589,15 +593,16 @@ describe('GroupProfileSlug', () => {
|
||||
'auth/isModerator': () => false,
|
||||
},
|
||||
}
|
||||
wrapper = Wrapper()
|
||||
wrapper.setData({
|
||||
Group: [
|
||||
{
|
||||
...yogaPractice,
|
||||
myRole: null,
|
||||
},
|
||||
],
|
||||
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
|
||||
wrapper = Wrapper(() => {
|
||||
return {
|
||||
Group: [
|
||||
{
|
||||
...yogaPractice,
|
||||
myRole: null,
|
||||
},
|
||||
],
|
||||
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@ -705,15 +710,16 @@ describe('GroupProfileSlug', () => {
|
||||
'auth/isModerator': () => false,
|
||||
},
|
||||
}
|
||||
wrapper = Wrapper()
|
||||
wrapper.setData({
|
||||
Group: [
|
||||
{
|
||||
...schoolForCitizens,
|
||||
myRole: 'owner',
|
||||
},
|
||||
],
|
||||
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
|
||||
wrapper = Wrapper(() => {
|
||||
return {
|
||||
Group: [
|
||||
{
|
||||
...schoolForCitizens,
|
||||
myRole: 'owner',
|
||||
},
|
||||
],
|
||||
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@ -821,15 +827,16 @@ describe('GroupProfileSlug', () => {
|
||||
'auth/isModerator': () => false,
|
||||
},
|
||||
}
|
||||
wrapper = Wrapper()
|
||||
wrapper.setData({
|
||||
Group: [
|
||||
{
|
||||
...schoolForCitizens,
|
||||
myRole: 'usual',
|
||||
},
|
||||
],
|
||||
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
|
||||
wrapper = Wrapper(() => {
|
||||
return {
|
||||
Group: [
|
||||
{
|
||||
...schoolForCitizens,
|
||||
myRole: 'usual',
|
||||
},
|
||||
],
|
||||
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@ -937,15 +944,16 @@ describe('GroupProfileSlug', () => {
|
||||
'auth/isModerator': () => false,
|
||||
},
|
||||
}
|
||||
wrapper = Wrapper()
|
||||
wrapper.setData({
|
||||
Group: [
|
||||
{
|
||||
...schoolForCitizens,
|
||||
myRole: 'pending',
|
||||
},
|
||||
],
|
||||
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
|
||||
wrapper = Wrapper(() => {
|
||||
return {
|
||||
Group: [
|
||||
{
|
||||
...schoolForCitizens,
|
||||
myRole: 'pending',
|
||||
},
|
||||
],
|
||||
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@ -1053,15 +1061,16 @@ describe('GroupProfileSlug', () => {
|
||||
'auth/isModerator': () => false,
|
||||
},
|
||||
}
|
||||
wrapper = Wrapper()
|
||||
wrapper.setData({
|
||||
Group: [
|
||||
{
|
||||
...schoolForCitizens,
|
||||
myRole: null,
|
||||
},
|
||||
],
|
||||
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
|
||||
wrapper = Wrapper(() => {
|
||||
return {
|
||||
Group: [
|
||||
{
|
||||
...schoolForCitizens,
|
||||
myRole: null,
|
||||
},
|
||||
],
|
||||
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@ -1173,15 +1182,16 @@ describe('GroupProfileSlug', () => {
|
||||
'auth/isModerator': () => false,
|
||||
},
|
||||
}
|
||||
wrapper = Wrapper()
|
||||
wrapper.setData({
|
||||
Group: [
|
||||
{
|
||||
...investigativeJournalism,
|
||||
myRole: 'owner',
|
||||
},
|
||||
],
|
||||
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
|
||||
wrapper = Wrapper(() => {
|
||||
return {
|
||||
Group: [
|
||||
{
|
||||
...investigativeJournalism,
|
||||
myRole: 'owner',
|
||||
},
|
||||
],
|
||||
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@ -1292,15 +1302,16 @@ describe('GroupProfileSlug', () => {
|
||||
'auth/isModerator': () => false,
|
||||
},
|
||||
}
|
||||
wrapper = Wrapper()
|
||||
wrapper.setData({
|
||||
Group: [
|
||||
{
|
||||
...investigativeJournalism,
|
||||
myRole: 'usual',
|
||||
},
|
||||
],
|
||||
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
|
||||
wrapper = Wrapper(() => {
|
||||
return {
|
||||
Group: [
|
||||
{
|
||||
...investigativeJournalism,
|
||||
myRole: 'usual',
|
||||
},
|
||||
],
|
||||
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@ -1411,15 +1422,16 @@ describe('GroupProfileSlug', () => {
|
||||
'auth/isModerator': () => false,
|
||||
},
|
||||
}
|
||||
wrapper = Wrapper()
|
||||
wrapper.setData({
|
||||
Group: [
|
||||
{
|
||||
...investigativeJournalism,
|
||||
myRole: 'pending',
|
||||
},
|
||||
],
|
||||
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
|
||||
wrapper = Wrapper(() => {
|
||||
return {
|
||||
Group: [
|
||||
{
|
||||
...investigativeJournalism,
|
||||
myRole: 'pending',
|
||||
},
|
||||
],
|
||||
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@ -1518,15 +1530,16 @@ describe('GroupProfileSlug', () => {
|
||||
'auth/isModerator': () => false,
|
||||
},
|
||||
}
|
||||
wrapper = Wrapper()
|
||||
wrapper.setData({
|
||||
Group: [
|
||||
{
|
||||
...investigativeJournalism,
|
||||
myRole: null,
|
||||
},
|
||||
],
|
||||
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
|
||||
wrapper = Wrapper(() => {
|
||||
return {
|
||||
Group: [
|
||||
{
|
||||
...investigativeJournalism,
|
||||
myRole: null,
|
||||
},
|
||||
],
|
||||
GroupMembers: [peterLustig, jennyRostock, bobDerBaumeister, huey],
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@ -250,10 +250,9 @@
|
||||
</base-card>
|
||||
</ds-space>
|
||||
<ds-space v-if="isGroupMemberNonePending" centered>
|
||||
<nuxt-link :to="{ name: 'post-create' }">
|
||||
<nuxt-link :to="{ name: 'post-create', query: { groupId: group.id } }">
|
||||
<base-button
|
||||
class="profile-post-add-button"
|
||||
:path="{ name: 'post-create' }"
|
||||
icon="plus"
|
||||
circle
|
||||
filled
|
||||
@ -297,9 +296,9 @@
|
||||
</ds-grid-item>
|
||||
</template>
|
||||
</masonry-grid>
|
||||
<!-- <client-only>
|
||||
<client-only>
|
||||
<infinite-loading v-if="hasMore" @infinite="showMoreContributions" />
|
||||
</client-only> -->
|
||||
</client-only>
|
||||
</ds-flex-item>
|
||||
</ds-flex>
|
||||
</div>
|
||||
@ -307,11 +306,11 @@
|
||||
|
||||
<script>
|
||||
import uniqBy from 'lodash/uniqBy'
|
||||
// import { profilePagePosts } from '~/graphql/PostQuery'
|
||||
import { profilePagePosts } from '~/graphql/PostQuery'
|
||||
import { updateGroupMutation, groupQuery, groupMembersQuery } from '~/graphql/groups'
|
||||
// import { muteUser, unmuteUser } from '~/graphql/settings/MutedUsers'
|
||||
// import { blockUser, unblockUser } from '~/graphql/settings/BlockedUsers'
|
||||
// import UpdateQuery from '~/components/utils/UpdateQuery'
|
||||
import UpdateQuery from '~/components/utils/UpdateQuery'
|
||||
import postListActions from '~/mixins/postListActions'
|
||||
import AvatarUploader from '~/components/Uploader/AvatarUploader'
|
||||
import Category from '~/components/Category'
|
||||
@ -369,17 +368,16 @@ export default {
|
||||
},
|
||||
data() {
|
||||
// const filter = tabToFilterMapping({ tab: 'post', id: this.$route.params.id })
|
||||
const filter = { group: { id: this.$route.params.id } }
|
||||
return {
|
||||
categoriesActive: this.$env.CATEGORIES_ACTIVE,
|
||||
Group: [],
|
||||
GroupMembers: [],
|
||||
loadGroupMembers: false,
|
||||
posts: [],
|
||||
// hasMore: true,
|
||||
// offset: 0,
|
||||
// pageSize: 6,
|
||||
hasMore: true,
|
||||
offset: 0,
|
||||
pageSize: 6,
|
||||
// tabActive: 'post',
|
||||
// filter,
|
||||
filter,
|
||||
// followedByCountStartValue: 0,
|
||||
// followedByCount: 7,
|
||||
// followingCount: 7,
|
||||
@ -468,30 +466,30 @@ export default {
|
||||
uniq(items, field = 'id') {
|
||||
return uniqBy(items, field)
|
||||
},
|
||||
// showMoreContributions($state) {
|
||||
// const { profilePagePosts: PostQuery } = this.$apollo.queries
|
||||
// if (!PostQuery) return // seems this can be undefined on subpages
|
||||
// this.offset += this.pageSize
|
||||
showMoreContributions($state) {
|
||||
const { profilePagePosts: PostQuery } = this.$apollo.queries
|
||||
if (!PostQuery) return // seems this can be undefined on subpages
|
||||
this.offset += this.pageSize
|
||||
|
||||
// PostQuery.fetchMore({
|
||||
// variables: {
|
||||
// offset: this.offset,
|
||||
// filter: this.filter,
|
||||
// first: this.pageSize,
|
||||
// orderBy: 'createdAt_desc',
|
||||
// },
|
||||
// updateQuery: UpdateQuery(this, { $state, pageKey: 'profilePagePosts' }),
|
||||
// })
|
||||
// },
|
||||
// resetPostList() {
|
||||
// this.offset = 0
|
||||
// this.posts = []
|
||||
// this.hasMore = true
|
||||
// },
|
||||
// refetchPostList() {
|
||||
// this.resetPostList()
|
||||
// this.$apollo.queries.profilePagePosts.refetch()
|
||||
// },
|
||||
PostQuery.fetchMore({
|
||||
variables: {
|
||||
offset: this.offset,
|
||||
filter: this.filter,
|
||||
first: this.pageSize,
|
||||
orderBy: 'createdAt_desc',
|
||||
},
|
||||
updateQuery: UpdateQuery(this, { $state, pageKey: 'profilePagePosts' }),
|
||||
})
|
||||
},
|
||||
resetPostList() {
|
||||
this.offset = 0
|
||||
this.posts = []
|
||||
this.hasMore = true
|
||||
},
|
||||
refetchPostList() {
|
||||
this.resetPostList()
|
||||
this.$apollo.queries.profilePagePosts.refetch()
|
||||
},
|
||||
// async muteUser(user) {
|
||||
// try {
|
||||
// await this.$apollo.mutate({ mutation: muteUser(), variables: { id: user.id } })
|
||||
@ -578,23 +576,23 @@ export default {
|
||||
},
|
||||
},
|
||||
apollo: {
|
||||
// profilePagePosts: {
|
||||
// query() {
|
||||
// return profilePagePosts(this.$i18n)
|
||||
// },
|
||||
// variables() {
|
||||
// return {
|
||||
// filter: this.filter,
|
||||
// first: this.pageSize,
|
||||
// offset: 0,
|
||||
// orderBy: 'createdAt_desc',
|
||||
// }
|
||||
// },
|
||||
// update({ profilePagePosts }) {
|
||||
// this.posts = profilePagePosts
|
||||
// },
|
||||
// fetchPolicy: 'cache-and-network',
|
||||
// },
|
||||
profilePagePosts: {
|
||||
query() {
|
||||
return profilePagePosts(this.$i18n)
|
||||
},
|
||||
variables() {
|
||||
return {
|
||||
filter: this.filter,
|
||||
first: this.pageSize,
|
||||
offset: 0,
|
||||
orderBy: 'createdAt_desc',
|
||||
}
|
||||
},
|
||||
update({ profilePagePosts }) {
|
||||
this.posts = profilePagePosts
|
||||
},
|
||||
fetchPolicy: 'cache-and-network',
|
||||
},
|
||||
Group: {
|
||||
query() {
|
||||
return groupQuery(this.$i18n)
|
||||
|
||||
@ -3,7 +3,11 @@
|
||||
<base-card>
|
||||
<ds-heading tag="h3">{{ $t('group.members') }}</ds-heading>
|
||||
<ds-space margin="large" />
|
||||
<group-member :groupId="group.id" :groupMembers="groupMembers" />
|
||||
<group-member
|
||||
:groupId="group.id"
|
||||
:groupMembers="groupMembers"
|
||||
@loadGroupMembers="loadGroupMembers"
|
||||
/>
|
||||
</base-card>
|
||||
</div>
|
||||
</template>
|
||||
@ -44,5 +48,10 @@ export default {
|
||||
fetchPolicy: 'cache-and-network',
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
loadGroupMembers() {
|
||||
this.$apollo.queries.GroupMembers.refetch()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
<ds-grid-item v-if="showDonations" class="top-info-bar" :row-span="1" column-span="fullWidth">
|
||||
<donation-info :goal="goal" :progress="progress" />
|
||||
</ds-grid-item>
|
||||
<!-- newsfeed -->
|
||||
<!-- news feed -->
|
||||
<template v-if="hasResults">
|
||||
<masonry-grid-item
|
||||
v-for="post in posts"
|
||||
|
||||
@ -1,16 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<ds-flex gutter="small">
|
||||
<ds-flex-item :width="{ base: '100%', sm: 2, md: 2, lg: 1 }">
|
||||
<transition name="slide-up" appear>
|
||||
<nuxt-child />
|
||||
</transition>
|
||||
</ds-flex-item>
|
||||
<ds-flex-item :width="{ base: '200px' }">
|
||||
<ds-menu :routes="routes" class="post-side-navigation" />
|
||||
</ds-flex-item>
|
||||
</ds-flex>
|
||||
</div>
|
||||
<transition name="slide-up" appear>
|
||||
<nuxt-child />
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@ -41,40 +32,5 @@ const persistentLinks = PersistentLinks(options)
|
||||
|
||||
export default {
|
||||
mixins: [persistentLinks],
|
||||
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`
|
||||
} */
|
||||
],
|
||||
},
|
||||
]
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.post-side-navigation {
|
||||
position: sticky;
|
||||
top: 65px;
|
||||
z-index: 2;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -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: {
|
||||
|
||||
@ -1,107 +1,129 @@
|
||||
<template>
|
||||
<transition name="fade" appear>
|
||||
<base-card
|
||||
v-if="post && ready"
|
||||
:lang="post.language"
|
||||
:class="{
|
||||
'post-page': true,
|
||||
'disabled-content': post.disabled,
|
||||
'--blur-image': blurred,
|
||||
}"
|
||||
:style="heroImageStyle"
|
||||
>
|
||||
<template #heroImage v-if="post.image">
|
||||
<img :src="post.image | proxyApiUrl" class="image" />
|
||||
<aside v-show="post.image && post.image.sensitive" class="blur-toggle">
|
||||
<img v-show="blurred" :src="post.image | proxyApiUrl" class="preview" />
|
||||
<base-button
|
||||
:icon="blurred ? 'eye' : 'eye-slash'"
|
||||
filled
|
||||
circle
|
||||
@click="blurred = !blurred"
|
||||
/>
|
||||
</aside>
|
||||
</template>
|
||||
<section class="menu">
|
||||
<user-teaser :user="post.author" :date-time="post.createdAt">
|
||||
<template #dateTime>
|
||||
<ds-text v-if="post.createdAt !== post.updatedAt">({{ $t('post.edited') }})</ds-text>
|
||||
</template>
|
||||
</user-teaser>
|
||||
<client-only>
|
||||
<content-menu
|
||||
placement="bottom-end"
|
||||
resource-type="contribution"
|
||||
:resource="post"
|
||||
:modalsData="menuModalsData"
|
||||
:is-owner="isAuthor"
|
||||
@pinPost="pinPost"
|
||||
@unpinPost="unpinPost"
|
||||
/>
|
||||
</client-only>
|
||||
</section>
|
||||
<ds-space margin-bottom="small" />
|
||||
<h2 class="title hyphenate-text">{{ post.title }}</h2>
|
||||
<ds-space margin-bottom="small" />
|
||||
<content-viewer class="content hyphenate-text" :content="post.content" />
|
||||
<!-- Categories -->
|
||||
<div v-if="categoriesActive" class="categories">
|
||||
<ds-space margin="xx-large" />
|
||||
<ds-space margin="xx-small" />
|
||||
<hc-category
|
||||
v-for="category in post.categories"
|
||||
:key="category.id"
|
||||
:icon="category.icon"
|
||||
:name="$t(`contribution.category.name.${category.slug}`)"
|
||||
v-tooltip="{
|
||||
content: $t(`contribution.category.description.${category.slug}`),
|
||||
placement: 'bottom-start',
|
||||
}"
|
||||
/>
|
||||
</div>
|
||||
<ds-space margin-bottom="small" />
|
||||
<!-- Tags -->
|
||||
<div v-if="post.tags && post.tags.length" class="tags">
|
||||
<ds-space margin="xx-small" />
|
||||
<hc-hashtag v-for="tag in sortedTags" :key="tag.id" :id="tag.id" />
|
||||
</div>
|
||||
<ds-space margin-top="small">
|
||||
<ds-flex :gutter="{ lg: 'small' }">
|
||||
<!-- Shout Button -->
|
||||
<ds-flex-item
|
||||
:width="{ lg: '15%', md: '22%', sm: '22%', base: '100%' }"
|
||||
class="shout-button"
|
||||
>
|
||||
<hc-shout-button
|
||||
v-if="post.author"
|
||||
:disabled="isAuthor"
|
||||
:count="post.shoutedCount"
|
||||
:is-shouted="post.shoutedByCurrentUser"
|
||||
:post-id="post.id"
|
||||
/>
|
||||
</ds-flex-item>
|
||||
</ds-flex>
|
||||
<div>
|
||||
<ds-space margin="small">
|
||||
<ds-heading tag="h1">{{ $t('post.viewPost.title') }}</ds-heading>
|
||||
<ds-heading v-if="post && post.group" tag="h2">
|
||||
{{ $t('post.viewPost.forGroup.title', { name: post.group.name }) }}
|
||||
</ds-heading>
|
||||
</ds-space>
|
||||
<!-- Comments -->
|
||||
<ds-section>
|
||||
<comment-list :post="post" @toggleNewCommentForm="toggleNewCommentForm" @reply="reply" />
|
||||
<ds-space margin-bottom="large" />
|
||||
<comment-form
|
||||
v-if="showNewCommentForm && !isBlocked"
|
||||
ref="commentForm"
|
||||
:post="post"
|
||||
@createComment="createComment"
|
||||
/>
|
||||
<ds-placeholder v-if="isBlocked">
|
||||
{{ $t('settings.blocked-users.explanation.commenting-disabled') }}
|
||||
<br />
|
||||
{{ $t('settings.blocked-users.explanation.commenting-explanation') }}
|
||||
<page-params-link :pageParams="links.FAQ">
|
||||
{{ $t('site.faq') }}
|
||||
</page-params-link>
|
||||
</ds-placeholder>
|
||||
</ds-section>
|
||||
</base-card>
|
||||
<ds-space margin="large" />
|
||||
<ds-flex gutter="small">
|
||||
<ds-flex-item :width="{ base: '100%', sm: 2, md: 2, lg: 1 }">
|
||||
<base-card
|
||||
v-if="post && ready"
|
||||
:lang="post.language"
|
||||
:class="{
|
||||
'post-page': true,
|
||||
'disabled-content': post.disabled,
|
||||
'--blur-image': blurred,
|
||||
}"
|
||||
:style="heroImageStyle"
|
||||
>
|
||||
<template #heroImage v-if="post.image">
|
||||
<img :src="post.image | proxyApiUrl" class="image" />
|
||||
<aside v-show="post.image && post.image.sensitive" class="blur-toggle">
|
||||
<img v-show="blurred" :src="post.image | proxyApiUrl" class="preview" />
|
||||
<base-button
|
||||
:icon="blurred ? 'eye' : 'eye-slash'"
|
||||
filled
|
||||
circle
|
||||
@click="blurred = !blurred"
|
||||
/>
|
||||
</aside>
|
||||
</template>
|
||||
<section class="menu">
|
||||
<user-teaser :user="post.author" :date-time="post.createdAt">
|
||||
<template #dateTime>
|
||||
<ds-text v-if="post.createdAt !== post.updatedAt">
|
||||
({{ $t('post.edited') }})
|
||||
</ds-text>
|
||||
</template>
|
||||
</user-teaser>
|
||||
<client-only>
|
||||
<content-menu
|
||||
placement="bottom-end"
|
||||
resource-type="contribution"
|
||||
:resource="post"
|
||||
:modalsData="menuModalsData"
|
||||
:is-owner="isAuthor"
|
||||
@pinPost="pinPost"
|
||||
@unpinPost="unpinPost"
|
||||
/>
|
||||
</client-only>
|
||||
</section>
|
||||
<ds-space margin-bottom="small" />
|
||||
<h2 class="title hyphenate-text">{{ post.title }}</h2>
|
||||
<ds-space margin-bottom="small" />
|
||||
<content-viewer class="content hyphenate-text" :content="post.content" />
|
||||
<!-- Categories -->
|
||||
<div v-if="categoriesActive" class="categories">
|
||||
<ds-space margin="xx-large" />
|
||||
<ds-space margin="xx-small" />
|
||||
<hc-category
|
||||
v-for="category in post.categories"
|
||||
:key="category.id"
|
||||
:icon="category.icon"
|
||||
:name="$t(`contribution.category.name.${category.slug}`)"
|
||||
v-tooltip="{
|
||||
content: $t(`contribution.category.description.${category.slug}`),
|
||||
placement: 'bottom-start',
|
||||
}"
|
||||
/>
|
||||
</div>
|
||||
<ds-space margin-bottom="small" />
|
||||
<!-- Tags -->
|
||||
<div v-if="post.tags && post.tags.length" class="tags">
|
||||
<ds-space margin="xx-small" />
|
||||
<hc-hashtag v-for="tag in sortedTags" :key="tag.id" :id="tag.id" />
|
||||
</div>
|
||||
<ds-space margin-top="small">
|
||||
<ds-flex :gutter="{ lg: 'small' }">
|
||||
<!-- Shout Button -->
|
||||
<ds-flex-item
|
||||
:width="{ lg: '15%', md: '22%', sm: '22%', base: '100%' }"
|
||||
class="shout-button"
|
||||
>
|
||||
<hc-shout-button
|
||||
v-if="post.author"
|
||||
:disabled="isAuthor"
|
||||
:count="post.shoutedCount"
|
||||
:is-shouted="post.shoutedByCurrentUser"
|
||||
:post-id="post.id"
|
||||
/>
|
||||
</ds-flex-item>
|
||||
</ds-flex>
|
||||
</ds-space>
|
||||
<!-- Comments -->
|
||||
<ds-section>
|
||||
<comment-list
|
||||
:post="post"
|
||||
@toggleNewCommentForm="toggleNewCommentForm"
|
||||
@reply="reply"
|
||||
/>
|
||||
<ds-space margin-bottom="large" />
|
||||
<comment-form
|
||||
v-if="showNewCommentForm && !isBlocked"
|
||||
ref="commentForm"
|
||||
:post="post"
|
||||
@createComment="createComment"
|
||||
/>
|
||||
<ds-placeholder v-if="isBlocked">
|
||||
{{ $t('settings.blocked-users.explanation.commenting-disabled') }}
|
||||
<br />
|
||||
{{ $t('settings.blocked-users.explanation.commenting-explanation') }}
|
||||
<page-params-link :pageParams="links.FAQ">
|
||||
{{ $t('site.faq') }}
|
||||
</page-params-link>
|
||||
</ds-placeholder>
|
||||
</ds-section>
|
||||
</base-card>
|
||||
</ds-flex-item>
|
||||
<ds-flex-item :width="{ base: '200px' }">
|
||||
<ds-menu :routes="routes" class="post-side-navigation" />
|
||||
</ds-flex-item>
|
||||
</ds-flex>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
@ -167,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 …
|
||||
@ -266,6 +313,11 @@ export default {
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.post-side-navigation {
|
||||
position: sticky;
|
||||
top: 65px;
|
||||
z-index: 2;
|
||||
}
|
||||
.post-page {
|
||||
> .hero-image {
|
||||
position: relative;
|
||||
|
||||
@ -11,6 +11,11 @@ describe('create.vue', () => {
|
||||
$env: {
|
||||
CATEGORIES_ACTIVE: false,
|
||||
},
|
||||
$route: {
|
||||
query: {
|
||||
groupId: null,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
describe('mount', () => {
|
||||
|
||||
@ -1,18 +1,60 @@
|
||||
<template>
|
||||
<ds-flex :width="{ base: '100%' }" gutter="base">
|
||||
<ds-flex-item :width="{ base: '100%', md: 5 }">
|
||||
<hc-contribution-form />
|
||||
</ds-flex-item>
|
||||
<ds-flex-item :width="{ base: '100%', md: 1 }"> </ds-flex-item>
|
||||
</ds-flex>
|
||||
<div>
|
||||
<ds-space margin="small">
|
||||
<ds-heading tag="h1">{{ $t('post.createNewPost.title') }}</ds-heading>
|
||||
<ds-heading v-if="group" tag="h2">
|
||||
{{ $t('post.createNewPost.forGroup.title', { name: group.name }) }}
|
||||
</ds-heading>
|
||||
</ds-space>
|
||||
<ds-space margin="large" />
|
||||
<ds-flex :width="{ base: '100%' }" gutter="base">
|
||||
<ds-flex-item :width="{ base: '100%', md: 5 }">
|
||||
<contribution-form :groupId="groupId" />
|
||||
</ds-flex-item>
|
||||
<ds-flex-item :width="{ base: '100%', md: 1 }"> </ds-flex-item>
|
||||
</ds-flex>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import HcContributionForm from '~/components/ContributionForm/ContributionForm'
|
||||
import { groupQuery } from '~/graphql/groups'
|
||||
import ContributionForm from '~/components/ContributionForm/ContributionForm'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
HcContributionForm,
|
||||
ContributionForm,
|
||||
},
|
||||
data() {
|
||||
const { groupId = null } = this.$route.query
|
||||
return {
|
||||
groupId,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
group() {
|
||||
return this.Group && this.Group[0] ? this.Group[0] : null
|
||||
},
|
||||
},
|
||||
apollo: {
|
||||
Group: {
|
||||
query() {
|
||||
return groupQuery(this.$i18n)
|
||||
},
|
||||
variables() {
|
||||
return {
|
||||
id: this.groupId,
|
||||
// followedByCount: this.followedByCount,
|
||||
// followingCount: this.followingCount,
|
||||
}
|
||||
},
|
||||
skip() {
|
||||
return !this.groupId
|
||||
},
|
||||
error(error) {
|
||||
this.$toast.error(error.message)
|
||||
},
|
||||
fetchPolicy: 'cache-and-network',
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -1,20 +1,29 @@
|
||||
<template>
|
||||
<ds-flex :width="{ base: '100%' }" gutter="base">
|
||||
<ds-flex-item :width="{ base: '100%', md: 3 }">
|
||||
<hc-contribution-form :contribution="contribution" />
|
||||
</ds-flex-item>
|
||||
<ds-flex-item :width="{ base: '100%', md: 1 }"> </ds-flex-item>
|
||||
</ds-flex>
|
||||
<div>
|
||||
<ds-space margin="small">
|
||||
<ds-heading tag="h1">{{ $t('post.editPost.title') }}</ds-heading>
|
||||
<ds-heading v-if="contribution && contribution.group" tag="h2">
|
||||
{{ $t('post.editPost.forGroup.title', { name: contribution.group.name }) }}
|
||||
</ds-heading>
|
||||
</ds-space>
|
||||
<ds-space margin="large" />
|
||||
<ds-flex :width="{ base: '100%' }" gutter="base">
|
||||
<ds-flex-item :width="{ base: '100%', md: 3 }">
|
||||
<contribution-form :contribution="contribution" />
|
||||
</ds-flex-item>
|
||||
<ds-flex-item :width="{ base: '100%', md: 1 }"> </ds-flex-item>
|
||||
</ds-flex>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import HcContributionForm from '~/components/ContributionForm/ContributionForm'
|
||||
import ContributionForm from '~/components/ContributionForm/ContributionForm'
|
||||
import PostQuery from '~/graphql/PostQuery'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
HcContributionForm,
|
||||
ContributionForm,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user