mirror of
https://framagit.org/framasoft/mobilizon.git
synced 2024-12-21 23:44:30 +00:00
Add front-end for managing group follow
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
parent
244a349b7d
commit
f8eda4aac5
12 changed files with 217 additions and 20 deletions
|
@ -433,7 +433,7 @@ export const PERSON_MEMBERSHIPS = gql`
|
|||
}
|
||||
`;
|
||||
|
||||
export const PERSON_MEMBERSHIP_GROUP = gql`
|
||||
export const PERSON_STATUS_GROUP = gql`
|
||||
query PersonMembershipGroup($id: ID!, $group: String!) {
|
||||
person(id: $id) {
|
||||
id
|
||||
|
@ -461,6 +461,35 @@ export const PERSON_MEMBERSHIP_GROUP = gql`
|
|||
updatedAt
|
||||
}
|
||||
}
|
||||
follows(group: $group) {
|
||||
total
|
||||
elements {
|
||||
id
|
||||
notify
|
||||
target_actor {
|
||||
id
|
||||
preferredUsername
|
||||
name
|
||||
domain
|
||||
avatar {
|
||||
id
|
||||
url
|
||||
}
|
||||
}
|
||||
actor {
|
||||
id
|
||||
preferredUsername
|
||||
name
|
||||
domain
|
||||
avatar {
|
||||
id
|
||||
url
|
||||
}
|
||||
}
|
||||
insertedAt
|
||||
updatedAt
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -47,3 +47,28 @@ export const UPDATE_FOLLOWER = gql`
|
|||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const FOLLOW_GROUP = gql`
|
||||
mutation FollowGroup($groupId: ID!, $notify: Boolean) {
|
||||
followGroup(groupId: $groupId, notify: $notify) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const UNFOLLOW_GROUP = gql`
|
||||
mutation UnfollowGroup($groupId: ID!) {
|
||||
unfollowGroup(groupId: $groupId) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const UPDATE_GROUP_FOLLOW = gql`
|
||||
mutation UpdateGroupFollow($followId: ID!, $notify: Boolean) {
|
||||
updateGroupFollow(followId: $followId, notify: $notify) {
|
||||
id
|
||||
notify
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
import {
|
||||
CURRENT_ACTOR_CLIENT,
|
||||
GROUP_MEMBERSHIP_SUBSCRIPTION_CHANGED,
|
||||
PERSON_MEMBERSHIP_GROUP,
|
||||
PERSON_STATUS_GROUP,
|
||||
} from "@/graphql/actor";
|
||||
import { FETCH_GROUP } from "@/graphql/group";
|
||||
import RouteName from "@/router/name";
|
||||
import { IActor, IGroup, IPerson, usernameWithDomain } from "@/types/actor";
|
||||
import {
|
||||
IActor,
|
||||
IFollower,
|
||||
IGroup,
|
||||
IPerson,
|
||||
usernameWithDomain,
|
||||
} from "@/types/actor";
|
||||
import { MemberRole } from "@/types/enums";
|
||||
import { Component, Vue } from "vue-property-decorator";
|
||||
|
||||
|
@ -31,7 +37,7 @@ const now = new Date();
|
|||
},
|
||||
},
|
||||
person: {
|
||||
query: PERSON_MEMBERSHIP_GROUP,
|
||||
query: PERSON_STATUS_GROUP,
|
||||
fetchPolicy: "cache-and-network",
|
||||
variables() {
|
||||
return {
|
||||
|
@ -100,6 +106,21 @@ export default class GroupMixin extends Vue {
|
|||
);
|
||||
}
|
||||
|
||||
get isCurrentActorFollowing(): boolean {
|
||||
return this.currentActorFollow !== null;
|
||||
}
|
||||
|
||||
get isCurrentActorFollowingNotify(): boolean {
|
||||
return this.currentActorFollow?.notify === true;
|
||||
}
|
||||
|
||||
get currentActorFollow(): IFollower | null {
|
||||
if (this.person?.follows?.total > 0) {
|
||||
return this.person?.follows?.elements[0];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
handleErrors(errors: any[]): void {
|
||||
if (
|
||||
errors.some((error) => error.status_code === 404) ||
|
||||
|
|
|
@ -5,4 +5,5 @@ export interface IFollower {
|
|||
actor: IActor;
|
||||
targetActor: IActor;
|
||||
approved: boolean;
|
||||
notify?: boolean;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
export * from "./actor.model";
|
||||
export * from "./group.model";
|
||||
export * from "./person.model";
|
||||
export * from "./follower.model";
|
||||
|
|
|
@ -6,12 +6,14 @@ import type { Paginate } from "../paginate";
|
|||
import type { IParticipant } from "../participant.model";
|
||||
import type { IMember } from "./member.model";
|
||||
import type { IFeedToken } from "../feedtoken.model";
|
||||
import { IFollower } from "./follower.model";
|
||||
|
||||
export interface IPerson extends IActor {
|
||||
feedTokens: IFeedToken[];
|
||||
goingToEvents: IEvent[];
|
||||
participations: Paginate<IParticipant>;
|
||||
memberships: Paginate<IMember>;
|
||||
follows: Paginate<IFollower>;
|
||||
user?: ICurrentUser;
|
||||
}
|
||||
|
||||
|
@ -31,6 +33,7 @@ export class Person extends Actor implements IPerson {
|
|||
|
||||
this.patch(hash);
|
||||
}
|
||||
follows!: Paginate<IFollower>;
|
||||
|
||||
patch(hash: IPerson | Record<string, unknown>): void {
|
||||
Object.assign(this, hash);
|
||||
|
|
|
@ -89,7 +89,7 @@ import { MemberRole } from "@/types/enums";
|
|||
import {
|
||||
CURRENT_ACTOR_CLIENT,
|
||||
GROUP_MEMBERSHIP_SUBSCRIPTION_CHANGED,
|
||||
PERSON_MEMBERSHIP_GROUP,
|
||||
PERSON_STATUS_GROUP,
|
||||
} from "@/graphql/actor";
|
||||
import { IMember } from "@/types/actor/member.model";
|
||||
import EmptyContent from "@/components/Utils/EmptyContent.vue";
|
||||
|
@ -116,7 +116,7 @@ const DISCUSSIONS_PER_PAGE = 10;
|
|||
},
|
||||
},
|
||||
person: {
|
||||
query: PERSON_MEMBERSHIP_GROUP,
|
||||
query: PERSON_STATUS_GROUP,
|
||||
fetchPolicy: "cache-and-network",
|
||||
variables() {
|
||||
return {
|
||||
|
|
|
@ -607,7 +607,7 @@ import {
|
|||
IDENTITIES,
|
||||
LOGGED_USER_DRAFTS,
|
||||
LOGGED_USER_PARTICIPATIONS,
|
||||
PERSON_MEMBERSHIP_GROUP,
|
||||
PERSON_STATUS_GROUP,
|
||||
} from "../../graphql/actor";
|
||||
import {
|
||||
displayNameAndUsername,
|
||||
|
@ -669,7 +669,7 @@ const DEFAULT_LIMIT_NUMBER_OF_PLACES = 10;
|
|||
},
|
||||
},
|
||||
person: {
|
||||
query: PERSON_MEMBERSHIP_GROUP,
|
||||
query: PERSON_STATUS_GROUP,
|
||||
fetchPolicy: "cache-and-network",
|
||||
variables() {
|
||||
return {
|
||||
|
|
|
@ -496,10 +496,7 @@ import {
|
|||
FETCH_EVENT,
|
||||
JOIN_EVENT,
|
||||
} from "../../graphql/event";
|
||||
import {
|
||||
CURRENT_ACTOR_CLIENT,
|
||||
PERSON_MEMBERSHIP_GROUP,
|
||||
} from "../../graphql/actor";
|
||||
import { CURRENT_ACTOR_CLIENT, PERSON_STATUS_GROUP } from "../../graphql/actor";
|
||||
import { EventModel, IEvent } from "../../types/event.model";
|
||||
import { IActor, IPerson, Person, usernameWithDomain } from "../../types/actor";
|
||||
import { GRAPHQL_API_ENDPOINT } from "../../api/_entrypoint";
|
||||
|
@ -623,7 +620,7 @@ import { IUser } from "@/types/current-user.model";
|
|||
},
|
||||
},
|
||||
person: {
|
||||
query: PERSON_MEMBERSHIP_GROUP,
|
||||
query: PERSON_STATUS_GROUP,
|
||||
fetchPolicy: "cache-and-network",
|
||||
variables() {
|
||||
return {
|
||||
|
|
|
@ -164,6 +164,54 @@
|
|||
type="is-primary"
|
||||
>{{ $t("Join group") }}</b-button
|
||||
>
|
||||
<b-tooltip
|
||||
v-if="
|
||||
(!isCurrentActorFollowing || previewPublic) &&
|
||||
group.openness !== Openness.OPEN
|
||||
"
|
||||
:label="$t('This group is invite-only')"
|
||||
position="is-bottom"
|
||||
>
|
||||
<b-button disabled type="is-primary">{{
|
||||
$t("Follow 1")
|
||||
}}</b-button></b-tooltip
|
||||
>
|
||||
<b-button
|
||||
v-else-if="
|
||||
(!isCurrentActorFollowing || previewPublic) && currentActor.id
|
||||
"
|
||||
@click="followGroup"
|
||||
type="is-primary"
|
||||
:disabled="previewPublic"
|
||||
>{{ $t("Follow 2") }}</b-button
|
||||
>
|
||||
<b-button
|
||||
tag="router-link"
|
||||
:to="{
|
||||
name: RouteName.GROUP_FOLLOW,
|
||||
params: { preferredUsername: usernameWithDomain(group) },
|
||||
}"
|
||||
v-else-if="!isCurrentActorFollowing || previewPublic"
|
||||
:disabled="previewPublic"
|
||||
type="is-primary"
|
||||
>{{ $t("Follow 3") }}</b-button
|
||||
><b-button
|
||||
v-if="
|
||||
isCurrentActorFollowing && !previewPublic && currentActor.id
|
||||
"
|
||||
type="is-primary"
|
||||
@click="unFollowGroup"
|
||||
>{{ $t("Unfollow") }}</b-button
|
||||
>
|
||||
<b-button
|
||||
v-if="isCurrentActorFollowing"
|
||||
@click="toggleFollowNotify"
|
||||
:icon-left="
|
||||
isCurrentActorFollowingNotify
|
||||
? 'bell-outline'
|
||||
: 'bell-off-outline'
|
||||
"
|
||||
></b-button>
|
||||
<b-button
|
||||
outlined
|
||||
icon-left="share"
|
||||
|
@ -586,7 +634,7 @@ import { IMember } from "@/types/actor/member.model";
|
|||
import RouteName from "../../router/name";
|
||||
import GroupSection from "../../components/Group/GroupSection.vue";
|
||||
import ReportModal from "../../components/Report/ReportModal.vue";
|
||||
import { PERSON_MEMBERSHIP_GROUP } from "@/graphql/actor";
|
||||
import { PERSON_STATUS_GROUP } from "@/graphql/actor";
|
||||
import { LEAVE_GROUP } from "@/graphql/group";
|
||||
import LazyImageWrapper from "../../components/Image/LazyImageWrapper.vue";
|
||||
import EventMetadataBlock from "../../components/Event/EventMetadataBlock.vue";
|
||||
|
@ -594,6 +642,11 @@ import EmptyContent from "../../components/Utils/EmptyContent.vue";
|
|||
import { Paginate } from "@/types/paginate";
|
||||
import { IEvent } from "@/types/event.model";
|
||||
import { IPost } from "@/types/post.model";
|
||||
import {
|
||||
FOLLOW_GROUP,
|
||||
UNFOLLOW_GROUP,
|
||||
UPDATE_GROUP_FOLLOW,
|
||||
} from "@/graphql/followers";
|
||||
|
||||
@Component({
|
||||
apollo: {
|
||||
|
@ -674,7 +727,7 @@ export default class Group extends mixins(GroupMixin) {
|
|||
},
|
||||
refetchQueries: [
|
||||
{
|
||||
query: PERSON_MEMBERSHIP_GROUP,
|
||||
query: PERSON_STATUS_GROUP,
|
||||
variables: {
|
||||
id: currentActorId,
|
||||
group,
|
||||
|
@ -697,7 +750,7 @@ export default class Group extends mixins(GroupMixin) {
|
|||
},
|
||||
refetchQueries: [
|
||||
{
|
||||
query: PERSON_MEMBERSHIP_GROUP,
|
||||
query: PERSON_STATUS_GROUP,
|
||||
variables: {
|
||||
id: currentActorId,
|
||||
group,
|
||||
|
@ -712,6 +765,73 @@ export default class Group extends mixins(GroupMixin) {
|
|||
}
|
||||
}
|
||||
|
||||
async followGroup(): Promise<void> {
|
||||
try {
|
||||
const [group, currentActorId] = [
|
||||
usernameWithDomain(this.group),
|
||||
this.currentActor.id,
|
||||
];
|
||||
await this.$apollo.mutate({
|
||||
mutation: FOLLOW_GROUP,
|
||||
variables: {
|
||||
groupId: this.group.id,
|
||||
},
|
||||
refetchQueries: [
|
||||
{
|
||||
query: PERSON_STATUS_GROUP,
|
||||
variables: {
|
||||
id: currentActorId,
|
||||
group,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
} catch (error: any) {
|
||||
if (error.graphQLErrors && error.graphQLErrors.length > 0) {
|
||||
this.$notifier.error(error.graphQLErrors[0].message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async unFollowGroup(): Promise<void> {
|
||||
console.debug("unfollow group");
|
||||
try {
|
||||
const [group, currentActorId] = [
|
||||
usernameWithDomain(this.group),
|
||||
this.currentActor.id,
|
||||
];
|
||||
await this.$apollo.mutate({
|
||||
mutation: UNFOLLOW_GROUP,
|
||||
variables: {
|
||||
groupId: this.group.id,
|
||||
},
|
||||
refetchQueries: [
|
||||
{
|
||||
query: PERSON_STATUS_GROUP,
|
||||
variables: {
|
||||
id: currentActorId,
|
||||
group,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
} catch (error: any) {
|
||||
if (error.graphQLErrors && error.graphQLErrors.length > 0) {
|
||||
this.$notifier.error(error.graphQLErrors[0].message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async toggleFollowNotify(): Promise<void> {
|
||||
await this.$apollo.mutate({
|
||||
mutation: UPDATE_GROUP_FOLLOW,
|
||||
variables: {
|
||||
followId: this.currentActorFollow?.id,
|
||||
notify: !this.isCurrentActorFollowingNotify,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
acceptInvitation(): void {
|
||||
if (this.groupMember) {
|
||||
const index = this.person.memberships.elements.findIndex(
|
||||
|
|
|
@ -181,7 +181,7 @@ import TagInput from "../../components/Event/TagInput.vue";
|
|||
import RouteName from "../../router/name";
|
||||
import Subtitle from "../../components/Utils/Subtitle.vue";
|
||||
import PictureUpload from "../../components/PictureUpload.vue";
|
||||
import { PERSON_MEMBERSHIP_GROUP } from "@/graphql/actor";
|
||||
import { PERSON_STATUS_GROUP } from "@/graphql/actor";
|
||||
import { FETCH_GROUP } from "@/graphql/group";
|
||||
|
||||
@Component({
|
||||
|
@ -211,7 +211,7 @@ import { FETCH_GROUP } from "@/graphql/group";
|
|||
},
|
||||
},
|
||||
person: {
|
||||
query: PERSON_MEMBERSHIP_GROUP,
|
||||
query: PERSON_STATUS_GROUP,
|
||||
fetchPolicy: "cache-and-network",
|
||||
variables() {
|
||||
return {
|
||||
|
|
|
@ -120,7 +120,7 @@ import { IMember } from "@/types/actor/member.model";
|
|||
import {
|
||||
CURRENT_ACTOR_CLIENT,
|
||||
PERSON_MEMBERSHIPS,
|
||||
PERSON_MEMBERSHIP_GROUP,
|
||||
PERSON_STATUS_GROUP,
|
||||
} from "../../graphql/actor";
|
||||
import { FETCH_POST } from "../../graphql/post";
|
||||
import { IPost } from "../../types/post.model";
|
||||
|
@ -166,7 +166,7 @@ import { ICurrentUser } from "@/types/current-user.model";
|
|||
},
|
||||
},
|
||||
person: {
|
||||
query: PERSON_MEMBERSHIP_GROUP,
|
||||
query: PERSON_STATUS_GROUP,
|
||||
fetchPolicy: "cache-and-network",
|
||||
variables() {
|
||||
return {
|
||||
|
|
Loading…
Reference in a new issue