Add front-end for managing group follow
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
parent
244a349b7d
commit
f8eda4aac5
|
@ -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!) {
|
query PersonMembershipGroup($id: ID!, $group: String!) {
|
||||||
person(id: $id) {
|
person(id: $id) {
|
||||||
id
|
id
|
||||||
|
@ -461,6 +461,35 @@ export const PERSON_MEMBERSHIP_GROUP = gql`
|
||||||
updatedAt
|
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 {
|
import {
|
||||||
CURRENT_ACTOR_CLIENT,
|
CURRENT_ACTOR_CLIENT,
|
||||||
GROUP_MEMBERSHIP_SUBSCRIPTION_CHANGED,
|
GROUP_MEMBERSHIP_SUBSCRIPTION_CHANGED,
|
||||||
PERSON_MEMBERSHIP_GROUP,
|
PERSON_STATUS_GROUP,
|
||||||
} from "@/graphql/actor";
|
} from "@/graphql/actor";
|
||||||
import { FETCH_GROUP } from "@/graphql/group";
|
import { FETCH_GROUP } from "@/graphql/group";
|
||||||
import RouteName from "@/router/name";
|
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 { MemberRole } from "@/types/enums";
|
||||||
import { Component, Vue } from "vue-property-decorator";
|
import { Component, Vue } from "vue-property-decorator";
|
||||||
|
|
||||||
|
@ -31,7 +37,7 @@ const now = new Date();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
person: {
|
person: {
|
||||||
query: PERSON_MEMBERSHIP_GROUP,
|
query: PERSON_STATUS_GROUP,
|
||||||
fetchPolicy: "cache-and-network",
|
fetchPolicy: "cache-and-network",
|
||||||
variables() {
|
variables() {
|
||||||
return {
|
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 {
|
handleErrors(errors: any[]): void {
|
||||||
if (
|
if (
|
||||||
errors.some((error) => error.status_code === 404) ||
|
errors.some((error) => error.status_code === 404) ||
|
||||||
|
|
|
@ -5,4 +5,5 @@ export interface IFollower {
|
||||||
actor: IActor;
|
actor: IActor;
|
||||||
targetActor: IActor;
|
targetActor: IActor;
|
||||||
approved: boolean;
|
approved: boolean;
|
||||||
|
notify?: boolean;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
export * from "./actor.model";
|
export * from "./actor.model";
|
||||||
export * from "./group.model";
|
export * from "./group.model";
|
||||||
export * from "./person.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 { IParticipant } from "../participant.model";
|
||||||
import type { IMember } from "./member.model";
|
import type { IMember } from "./member.model";
|
||||||
import type { IFeedToken } from "../feedtoken.model";
|
import type { IFeedToken } from "../feedtoken.model";
|
||||||
|
import { IFollower } from "./follower.model";
|
||||||
|
|
||||||
export interface IPerson extends IActor {
|
export interface IPerson extends IActor {
|
||||||
feedTokens: IFeedToken[];
|
feedTokens: IFeedToken[];
|
||||||
goingToEvents: IEvent[];
|
goingToEvents: IEvent[];
|
||||||
participations: Paginate<IParticipant>;
|
participations: Paginate<IParticipant>;
|
||||||
memberships: Paginate<IMember>;
|
memberships: Paginate<IMember>;
|
||||||
|
follows: Paginate<IFollower>;
|
||||||
user?: ICurrentUser;
|
user?: ICurrentUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +33,7 @@ export class Person extends Actor implements IPerson {
|
||||||
|
|
||||||
this.patch(hash);
|
this.patch(hash);
|
||||||
}
|
}
|
||||||
|
follows!: Paginate<IFollower>;
|
||||||
|
|
||||||
patch(hash: IPerson | Record<string, unknown>): void {
|
patch(hash: IPerson | Record<string, unknown>): void {
|
||||||
Object.assign(this, hash);
|
Object.assign(this, hash);
|
||||||
|
|
|
@ -89,7 +89,7 @@ import { MemberRole } from "@/types/enums";
|
||||||
import {
|
import {
|
||||||
CURRENT_ACTOR_CLIENT,
|
CURRENT_ACTOR_CLIENT,
|
||||||
GROUP_MEMBERSHIP_SUBSCRIPTION_CHANGED,
|
GROUP_MEMBERSHIP_SUBSCRIPTION_CHANGED,
|
||||||
PERSON_MEMBERSHIP_GROUP,
|
PERSON_STATUS_GROUP,
|
||||||
} from "@/graphql/actor";
|
} from "@/graphql/actor";
|
||||||
import { IMember } from "@/types/actor/member.model";
|
import { IMember } from "@/types/actor/member.model";
|
||||||
import EmptyContent from "@/components/Utils/EmptyContent.vue";
|
import EmptyContent from "@/components/Utils/EmptyContent.vue";
|
||||||
|
@ -116,7 +116,7 @@ const DISCUSSIONS_PER_PAGE = 10;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
person: {
|
person: {
|
||||||
query: PERSON_MEMBERSHIP_GROUP,
|
query: PERSON_STATUS_GROUP,
|
||||||
fetchPolicy: "cache-and-network",
|
fetchPolicy: "cache-and-network",
|
||||||
variables() {
|
variables() {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -607,7 +607,7 @@ import {
|
||||||
IDENTITIES,
|
IDENTITIES,
|
||||||
LOGGED_USER_DRAFTS,
|
LOGGED_USER_DRAFTS,
|
||||||
LOGGED_USER_PARTICIPATIONS,
|
LOGGED_USER_PARTICIPATIONS,
|
||||||
PERSON_MEMBERSHIP_GROUP,
|
PERSON_STATUS_GROUP,
|
||||||
} from "../../graphql/actor";
|
} from "../../graphql/actor";
|
||||||
import {
|
import {
|
||||||
displayNameAndUsername,
|
displayNameAndUsername,
|
||||||
|
@ -669,7 +669,7 @@ const DEFAULT_LIMIT_NUMBER_OF_PLACES = 10;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
person: {
|
person: {
|
||||||
query: PERSON_MEMBERSHIP_GROUP,
|
query: PERSON_STATUS_GROUP,
|
||||||
fetchPolicy: "cache-and-network",
|
fetchPolicy: "cache-and-network",
|
||||||
variables() {
|
variables() {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -496,10 +496,7 @@ import {
|
||||||
FETCH_EVENT,
|
FETCH_EVENT,
|
||||||
JOIN_EVENT,
|
JOIN_EVENT,
|
||||||
} from "../../graphql/event";
|
} from "../../graphql/event";
|
||||||
import {
|
import { CURRENT_ACTOR_CLIENT, PERSON_STATUS_GROUP } from "../../graphql/actor";
|
||||||
CURRENT_ACTOR_CLIENT,
|
|
||||||
PERSON_MEMBERSHIP_GROUP,
|
|
||||||
} from "../../graphql/actor";
|
|
||||||
import { EventModel, IEvent } from "../../types/event.model";
|
import { EventModel, IEvent } from "../../types/event.model";
|
||||||
import { IActor, IPerson, Person, usernameWithDomain } from "../../types/actor";
|
import { IActor, IPerson, Person, usernameWithDomain } from "../../types/actor";
|
||||||
import { GRAPHQL_API_ENDPOINT } from "../../api/_entrypoint";
|
import { GRAPHQL_API_ENDPOINT } from "../../api/_entrypoint";
|
||||||
|
@ -623,7 +620,7 @@ import { IUser } from "@/types/current-user.model";
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
person: {
|
person: {
|
||||||
query: PERSON_MEMBERSHIP_GROUP,
|
query: PERSON_STATUS_GROUP,
|
||||||
fetchPolicy: "cache-and-network",
|
fetchPolicy: "cache-and-network",
|
||||||
variables() {
|
variables() {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -164,6 +164,54 @@
|
||||||
type="is-primary"
|
type="is-primary"
|
||||||
>{{ $t("Join group") }}</b-button
|
>{{ $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
|
<b-button
|
||||||
outlined
|
outlined
|
||||||
icon-left="share"
|
icon-left="share"
|
||||||
|
@ -586,7 +634,7 @@ import { IMember } from "@/types/actor/member.model";
|
||||||
import RouteName from "../../router/name";
|
import RouteName from "../../router/name";
|
||||||
import GroupSection from "../../components/Group/GroupSection.vue";
|
import GroupSection from "../../components/Group/GroupSection.vue";
|
||||||
import ReportModal from "../../components/Report/ReportModal.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 { LEAVE_GROUP } from "@/graphql/group";
|
||||||
import LazyImageWrapper from "../../components/Image/LazyImageWrapper.vue";
|
import LazyImageWrapper from "../../components/Image/LazyImageWrapper.vue";
|
||||||
import EventMetadataBlock from "../../components/Event/EventMetadataBlock.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 { Paginate } from "@/types/paginate";
|
||||||
import { IEvent } from "@/types/event.model";
|
import { IEvent } from "@/types/event.model";
|
||||||
import { IPost } from "@/types/post.model";
|
import { IPost } from "@/types/post.model";
|
||||||
|
import {
|
||||||
|
FOLLOW_GROUP,
|
||||||
|
UNFOLLOW_GROUP,
|
||||||
|
UPDATE_GROUP_FOLLOW,
|
||||||
|
} from "@/graphql/followers";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
apollo: {
|
apollo: {
|
||||||
|
@ -674,7 +727,7 @@ export default class Group extends mixins(GroupMixin) {
|
||||||
},
|
},
|
||||||
refetchQueries: [
|
refetchQueries: [
|
||||||
{
|
{
|
||||||
query: PERSON_MEMBERSHIP_GROUP,
|
query: PERSON_STATUS_GROUP,
|
||||||
variables: {
|
variables: {
|
||||||
id: currentActorId,
|
id: currentActorId,
|
||||||
group,
|
group,
|
||||||
|
@ -697,7 +750,7 @@ export default class Group extends mixins(GroupMixin) {
|
||||||
},
|
},
|
||||||
refetchQueries: [
|
refetchQueries: [
|
||||||
{
|
{
|
||||||
query: PERSON_MEMBERSHIP_GROUP,
|
query: PERSON_STATUS_GROUP,
|
||||||
variables: {
|
variables: {
|
||||||
id: currentActorId,
|
id: currentActorId,
|
||||||
group,
|
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 {
|
acceptInvitation(): void {
|
||||||
if (this.groupMember) {
|
if (this.groupMember) {
|
||||||
const index = this.person.memberships.elements.findIndex(
|
const index = this.person.memberships.elements.findIndex(
|
||||||
|
|
|
@ -181,7 +181,7 @@ import TagInput from "../../components/Event/TagInput.vue";
|
||||||
import RouteName from "../../router/name";
|
import RouteName from "../../router/name";
|
||||||
import Subtitle from "../../components/Utils/Subtitle.vue";
|
import Subtitle from "../../components/Utils/Subtitle.vue";
|
||||||
import PictureUpload from "../../components/PictureUpload.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";
|
import { FETCH_GROUP } from "@/graphql/group";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -211,7 +211,7 @@ import { FETCH_GROUP } from "@/graphql/group";
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
person: {
|
person: {
|
||||||
query: PERSON_MEMBERSHIP_GROUP,
|
query: PERSON_STATUS_GROUP,
|
||||||
fetchPolicy: "cache-and-network",
|
fetchPolicy: "cache-and-network",
|
||||||
variables() {
|
variables() {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -120,7 +120,7 @@ import { IMember } from "@/types/actor/member.model";
|
||||||
import {
|
import {
|
||||||
CURRENT_ACTOR_CLIENT,
|
CURRENT_ACTOR_CLIENT,
|
||||||
PERSON_MEMBERSHIPS,
|
PERSON_MEMBERSHIPS,
|
||||||
PERSON_MEMBERSHIP_GROUP,
|
PERSON_STATUS_GROUP,
|
||||||
} from "../../graphql/actor";
|
} from "../../graphql/actor";
|
||||||
import { FETCH_POST } from "../../graphql/post";
|
import { FETCH_POST } from "../../graphql/post";
|
||||||
import { IPost } from "../../types/post.model";
|
import { IPost } from "../../types/post.model";
|
||||||
|
@ -166,7 +166,7 @@ import { ICurrentUser } from "@/types/current-user.model";
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
person: {
|
person: {
|
||||||
query: PERSON_MEMBERSHIP_GROUP,
|
query: PERSON_STATUS_GROUP,
|
||||||
fetchPolicy: "cache-and-network",
|
fetchPolicy: "cache-and-network",
|
||||||
variables() {
|
variables() {
|
||||||
return {
|
return {
|
||||||
|
|
Loading…
Reference in a new issue