improve group creation view

This commit is contained in:
setop 2023-09-01 14:06:44 +00:00 committed by Thomas Citharel
parent 4ce79f5136
commit 3f60174877
6 changed files with 156 additions and 13 deletions

View file

@ -295,6 +295,10 @@ export const CREATE_GROUP = gql`
$summary: String $summary: String
$avatar: MediaInput $avatar: MediaInput
$banner: MediaInput $banner: MediaInput
$physicalAddress: AddressInput
$visibility: GroupVisibility
$openness: Openness
$manuallyApprovesFollowers: Boolean
) { ) {
createGroup( createGroup(
preferredUsername: $preferredUsername preferredUsername: $preferredUsername
@ -302,6 +306,10 @@ export const CREATE_GROUP = gql`
summary: $summary summary: $summary
banner: $banner banner: $banner
avatar: $avatar avatar: $avatar
physicalAddress: $physicalAddress
visibility: $visibility
openness: $openness
manuallyApprovesFollowers: $manuallyApprovesFollowers
) { ) {
...ActorFragment ...ActorFragment
banner { banner {

View file

@ -5,8 +5,7 @@ import type { IResource } from "../resource";
import type { IEvent } from "../event.model"; import type { IEvent } from "../event.model";
import type { IDiscussion } from "../discussions"; import type { IDiscussion } from "../discussions";
import type { IPost } from "../post.model"; import type { IPost } from "../post.model";
import type { IAddress } from "../address.model"; import { Address, type IAddress } from "../address.model";
import { Address } from "../address.model";
import { ActorType, GroupVisibility, Openness } from "../enums"; import { ActorType, GroupVisibility, Openness } from "../enums";
import type { IMember } from "./member.model"; import type { IMember } from "./member.model";
import type { ITodoList } from "../todolist"; import type { ITodoList } from "../todolist";
@ -53,11 +52,11 @@ export class Group extends Actor implements IGroup {
visibility: GroupVisibility = GroupVisibility.PUBLIC; visibility: GroupVisibility = GroupVisibility.PUBLIC;
activity: Paginate<IActivity> = { elements: [], total: 0 }; activity: Paginate<IActivity> = { elements: [], total: 0 };
openness: Openness = Openness.INVITE_ONLY; openness: Openness = Openness.MODERATED;
physicalAddress: IAddress = new Address(); physicalAddress: IAddress = new Address();
manuallyApprovesFollowers = true; manuallyApprovesFollowers = false;
patch(hash: IGroup | Record<string, unknown>): void { patch(hash: IGroup | Record<string, unknown>): void {
Object.assign(this, hash); Object.assign(this, hash);

View file

@ -120,7 +120,7 @@ import {
} from "vue-use-route-query"; } from "vue-use-route-query";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { useHead } from "@vueuse/head"; import { useHead } from "@vueuse/head";
import { computed, ref } from "vue"; import { computed } from "vue";
import { Paginate } from "@/types/paginate"; import { Paginate } from "@/types/paginate";
import { IGroup } from "@/types/actor"; import { IGroup } from "@/types/actor";
import AccountGroup from "vue-material-design-icons/AccountGroup.vue"; import AccountGroup from "vue-material-design-icons/AccountGroup.vue";

View file

@ -69,11 +69,25 @@
:message="summaryErrors[0]" :message="summaryErrors[0]"
:type="summaryErrors[1]" :type="summaryErrors[1]"
> >
<o-input v-model="group.summary" type="textarea" id="group-summary" /> <editor
v-if="currentActor"
id="group-summary"
mode="basic"
class="mb-3"
v-model="group.summary"
:maxSize="500"
:aria-label="$t('Group description body')"
:current-actor="currentActor"
/>
</o-field> </o-field>
<div> <full-address-auto-complete
<b>{{ t("Avatar") }}</b> :label="$t('Group address')"
v-model="group.physicalAddress"
/>
<div class="field">
<b class="field-label">{{ t("Avatar") }}</b>
<picture-upload <picture-upload
:textFallback="t('Avatar')" :textFallback="t('Avatar')"
v-model="avatarFile" v-model="avatarFile"
@ -81,8 +95,8 @@
/> />
</div> </div>
<div> <div class="field">
<b>{{ t("Banner") }}</b> <b class="field-label">{{ t("Banner") }}</b>
<picture-upload <picture-upload
:textFallback="t('Banner')" :textFallback="t('Banner')"
v-model="bannerFile" v-model="bannerFile"
@ -90,7 +104,101 @@
/> />
</div> </div>
<o-button variant="primary" native-type="submit"> <fieldset>
<legend class="field-label !mb-0 mt-2">
{{ t("Group visibility") }}
</legend>
<o-radio
v-model="group.visibility"
name="groupVisibility"
:native-value="GroupVisibility.PUBLIC"
>
{{ $t("Visible everywhere on the web") }}<br />
<small>{{
$t(
"The group will be publicly listed in search results and may be suggested in the explore section. Only public informations will be shown on it's page."
)
}}</small>
</o-radio>
<o-radio
v-model="group.visibility"
name="groupVisibility"
:native-value="GroupVisibility.UNLISTED"
>{{ $t("Only accessible through link") }}<br />
<small>{{
$t(
"You'll need to transmit the group URL so people may access the group's profile. The group won't be findable in Mobilizon's search or regular search engines."
)
}}</small>
</o-radio>
</fieldset>
<fieldset>
<legend class="mt-2">
<span class="field-label !mb-0">{{ t("New members") }} </span>
<span>
{{
t(
"Members will also access private sections like discussions, resources and restricted posts."
)
}}
</span>
</legend>
<o-field>
<o-radio
v-model="group.openness"
name="groupOpenness"
:native-value="Openness.OPEN"
>
{{ $t("Anyone can join freely") }}<br />
<small>{{
$t(
"Anyone wanting to be a member from your group will be able to from your group page."
)
}}</small>
</o-radio>
</o-field>
<o-field>
<o-radio
v-model="group.openness"
name="groupOpenness"
:native-value="Openness.MODERATED"
>{{ $t("Moderate new members") }}<br />
<small>{{
$t(
"Anyone can request being a member, but an administrator needs to approve the membership."
)
}}</small>
</o-radio>
</o-field>
<o-field>
<o-radio
v-model="group.openness"
name="groupOpenness"
:native-value="Openness.INVITE_ONLY"
>{{ $t("Manually invite new members") }}<br />
<small>{{
$t(
"The only way for your group to get new members is if an admininistrator invites them."
)
}}</small>
</o-radio>
</o-field>
</fieldset>
<fieldset>
<legend class="mt-2">
<span class="field-label !mb-0">
{{ t("Followers") }}
</span>
<span>
{{ t("Followers will receive new public events and posts.") }}
</span>
</legend>
<o-checkbox v-model="group.manuallyApprovesFollowers">
{{ t("Manually approve new followers") }}
</o-checkbox>
</fieldset>
<o-button variant="primary" native-type="submit" class="mt-3">
{{ t("Create my group") }} {{ t("Create my group") }}
</o-button> </o-button>
</form> </form>
@ -105,7 +213,14 @@ import PictureUpload from "../../components/PictureUpload.vue";
import { ErrorResponse } from "@/types/errors.model"; import { ErrorResponse } from "@/types/errors.model";
import { ServerParseError } from "@apollo/client/link/http"; import { ServerParseError } from "@apollo/client/link/http";
import { useCurrentActorClient } from "@/composition/apollo/actor"; import { useCurrentActorClient } from "@/composition/apollo/actor";
import { computed, inject, reactive, ref, watch } from "vue"; import {
computed,
defineAsyncComponent,
inject,
reactive,
ref,
watch,
} from "vue";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { useCreateGroup } from "@/composition/apollo/group"; import { useCreateGroup } from "@/composition/apollo/group";
@ -116,6 +231,12 @@ import {
} from "@/composition/config"; } from "@/composition/config";
import { Notifier } from "@/plugins/notifier"; import { Notifier } from "@/plugins/notifier";
import { useHead } from "@vueuse/head"; import { useHead } from "@vueuse/head";
import { Openness, GroupVisibility } from "@/types/enums";
import FullAddressAutoComplete from "@/components/Event/FullAddressAutoComplete.vue";
const Editor = defineAsyncComponent(
() => import("@/components/TextEditor.vue")
);
const { currentActor } = useCurrentActorClient(); const { currentActor } = useCurrentActorClient();
@ -156,10 +277,20 @@ const buildVariables = computed(() => {
let avatarObj = {}; let avatarObj = {};
let bannerObj = {}; let bannerObj = {};
const cloneGroup = group.value;
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
delete cloneGroup.physicalAddress.__typename;
delete cloneGroup.physicalAddress.pictureInfo;
const groupBasic = { const groupBasic = {
preferredUsername: group.value.preferredUsername, preferredUsername: group.value.preferredUsername,
name: group.value.name, name: group.value.name,
summary: group.value.summary, summary: group.value.summary,
physicalAddress: cloneGroup.physicalAddress,
visibility: group.value.visibility,
openness: group.value.openness,
manuallyApprovesFollowers: group.value.manuallyApprovesFollowers,
}; };
if (avatarFile.value) { if (avatarFile.value) {

View file

@ -305,6 +305,10 @@ defmodule Mobilizon.GraphQL.Schema.Actors.GroupType do
description: "Whether the group can be join freely, with approval or is invite-only." description: "Whether the group can be join freely, with approval or is invite-only."
) )
arg(:manually_approves_followers, :boolean,
description: "Whether this group approves new followers manually"
)
arg(:avatar, :media_input, arg(:avatar, :media_input,
description: description:
"The avatar for the group, either as an object or directly the ID of an existing media" "The avatar for the group, either as an object or directly the ID of an existing media"

View file

@ -146,7 +146,8 @@ defmodule Mobilizon.Actors.Actor do
:domain, :domain,
:summary, :summary,
:visibility, :visibility,
:openness :openness,
:manually_approves_followers
] ]
@group_creation_attrs @group_creation_required_attrs ++ @group_creation_optional_attrs @group_creation_attrs @group_creation_required_attrs ++ @group_creation_optional_attrs