diff --git a/webapp/assets/_new/styles/tokens.scss b/webapp/assets/_new/styles/tokens.scss index 6aa6410df..180f9c820 100644 --- a/webapp/assets/_new/styles/tokens.scss +++ b/webapp/assets/_new/styles/tokens.scss @@ -268,6 +268,7 @@ $size-avatar-large: 114px; * @presenter Spacing */ + $size-button-large: 50px; $size-button-base: 36px; $size-button-small: 26px; diff --git a/webapp/components/Group/GroupCard.vue b/webapp/components/Group/GroupCard.vue deleted file mode 100644 index 4afacaa38..000000000 --- a/webapp/components/Group/GroupCard.vue +++ /dev/null @@ -1,65 +0,0 @@ - - - diff --git a/webapp/components/Group/GroupContentMenu.vue b/webapp/components/Group/GroupContentMenu.vue index a9a667c57..929232bfe 100644 --- a/webapp/components/Group/GroupContentMenu.vue +++ b/webapp/components/Group/GroupContentMenu.vue @@ -40,7 +40,13 @@ export default { Dropdown, }, props: { - placement: { type: String, default: 'bottom-end' }, + usage: { + type: String, + required: true, + validator: (value) => { + return value.match(/(groupTeaser|groupProfile)/) + }, + }, resource: { type: Object, required: true }, resourceType: { type: String, @@ -49,6 +55,7 @@ export default { return value.match(/(group)/) }, }, + placement: { type: String, default: 'bottom-end' }, }, computed: { routes() { diff --git a/webapp/components/Group/GroupForm.spec.js b/webapp/components/Group/GroupForm.spec.js new file mode 100644 index 000000000..0300bacd0 --- /dev/null +++ b/webapp/components/Group/GroupForm.spec.js @@ -0,0 +1,39 @@ +import { config, mount } from '@vue/test-utils' +import GroupForm from './GroupForm.vue' + +const localVue = global.localVue + +config.stubs['nuxt-link'] = '' + +const propsData = { + update: false, + group: {}, +} + +describe('GroupForm', () => { + let wrapper + let mocks + + beforeEach(() => { + mocks = { + $t: jest.fn(), + $env: { + CATEGORIES_ACTIVE: true, + }, + } + }) + + describe('mount', () => { + const Wrapper = () => { + return mount(GroupForm, { propsData, mocks, localVue }) + } + + beforeEach(() => { + wrapper = Wrapper() + }) + + it('renders', () => { + expect(wrapper.findAll('.group-form')).toHaveLength(1) + }) + }) +}) diff --git a/webapp/components/Group/GroupForm.vue b/webapp/components/Group/GroupForm.vue index 8a9638b1a..daf0c1d2a 100644 --- a/webapp/components/Group/GroupForm.vue +++ b/webapp/components/Group/GroupForm.vue @@ -1,68 +1,132 @@ @@ -70,6 +134,9 @@ 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' +import { queryLocations } from '~/graphql/location' + +let timeout export default { name: 'GroupForm', @@ -89,24 +156,33 @@ export default { }, }, data() { - const { name, groupType, about, description, actionRadius, categories } = this.group + const { name, slug, groupType, about, description, actionRadius, locationName, categories } = + this.group return { categoriesActive: this.$env.CATEGORIES_ACTIVE, disabled: false, + groupTypeOptions: ['public', 'closed', 'hidden'], + actionRadiusOptions: ['regional', 'national', 'continental', 'global'], + loadingGeo: false, + cities: [], formData: { name: name || '', + slug: slug || '', groupType: groupType || '', about: about || '', description: description || '', + locationName: locationName || '', actionRadius: actionRadius || '', categoryIds: categories ? categories.map((category) => category.id) : [], }, formSchema: { name: { required: true, min: NAME_LENGTH_MIN, max: NAME_LENGTH_MAX }, + slug: { required: false }, groupType: { required: true }, about: { required: true }, description: { required: true }, actionRadius: { required: true }, + locationName: { required: false }, categoryIds: { type: 'array', required: this.categoriesActive, @@ -123,16 +199,54 @@ export default { }, } }, + computed: { + submitDisable() { + return ( + this.formData.name === '' || + this.formData.groupType === '' || + // this.formData.about === '' || // not mandatory + this.formData.description === '' || + this.formData.actionRadius === '' || + // this.formData.locationName === '' || // not mandatory + this.formData.categoryIds.length === 0 + ) + }, + submitDisableEdit() { + return ( + this.formData.name === this.group.name && + this.formData.slug === this.group.slug && + // this.formData.groupType === this.group.groupType && // can not be changed for now + this.formData.about === this.group.about && + this.formData.description === this.group.description && + this.formData.actionRadius === this.group.actionRadius && + this.formData.locationName === (this.group.locationName ? this.group.locationName : '') && + this.sameCategories + ) + }, + sameCategories() { + const formDataCategories = this.formData.categoryIds.map((id) => id).sort() + const groupDataCategories = this.group.categories.map((category) => category.id).sort() + let equal = true + if (formDataCategories.length !== groupDataCategories.length) return false + + formDataCategories.forEach((id, index) => { + equal = equal && id === groupDataCategories[index] + }) + return equal + }, + }, methods: { submit() { - const { name, about, description, groupType, actionRadius, categoryIds } = this.formData + const { name, about, description, groupType, actionRadius, locationName, categoryIds } = + this.formData const variables = { name, about, description, groupType, actionRadius, + locationName: locationName.label, categoryIds, } this.update @@ -142,9 +256,64 @@ export default { }) : this.$emit('createGroup', variables) }, - reset() { - alert('reset') + changeGroupType(event) { + this.formData.groupType = event.target.value + }, + changeActionRadius(event) { + this.formData.actionRadius = event.target.value + }, + handleCityInput(value) { + clearTimeout(timeout) + timeout = setTimeout(() => this.requestGeoData(value), 500) + }, + processLocationsResult(places) { + if (!places.length) { + return [] + } + const result = [] + places.forEach((place) => { + result.push({ + label: place.place_name, + value: place.place_name, + id: place.id, + }) + }) + + return result + }, + async requestGeoData(e) { + const value = e.target ? e.target.value.trim() : '' + if (value === '') { + this.cities = [] + return + } + this.loadingGeo = true + + const place = encodeURIComponent(value) + const lang = this.$i18n.locale() + + const { + data: { queryLocations: res }, + } = await this.$apollo.query({ query: queryLocations(), variables: { place, lang } }) + + this.cities = this.processLocationsResult(res) + this.loadingGeo = false }, }, } + + diff --git a/webapp/components/Group/GroupList.vue b/webapp/components/Group/GroupList.vue new file mode 100644 index 000000000..645f670d2 --- /dev/null +++ b/webapp/components/Group/GroupList.vue @@ -0,0 +1,21 @@ + + + diff --git a/webapp/components/Group/GroupMember.vue b/webapp/components/Group/GroupMember.vue index f522ee795..28412d33a 100644 --- a/webapp/components/Group/GroupMember.vue +++ b/webapp/components/Group/GroupMember.vue @@ -1,56 +1,148 @@