37
src/graphql/invitations.ts
Normal file
37
src/graphql/invitations.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import gql from "graphql-tag";
|
||||
|
||||
export const GROUP_INVITATIONS_LIST = gql`
|
||||
query ListInvitation($groupId: ID!) {
|
||||
listInvitations(groupId: $groupId) {
|
||||
label
|
||||
token
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const GROUP_INVITATIONS_CREATE = gql`
|
||||
mutation CreateInvitation($groupId: ID!, $label: String) {
|
||||
createInvitation(groupId: $groupId, label: $label) {
|
||||
label
|
||||
token
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const GROUP_INVITATIONS_UPDATE = gql`
|
||||
mutation UpdateInvitation($groupId: ID!, $token: String!, $label: String) {
|
||||
updateInvitation(groupId: $groupId, token: $token, label: $label) {
|
||||
label
|
||||
token
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const GROUP_INVITATIONS_DELETE = gql`
|
||||
mutation DeleteInvitation($groupId: ID!, $token: String!) {
|
||||
deleteInvitation(groupId: $groupId, token: $token) {
|
||||
label
|
||||
token
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -209,6 +209,7 @@
|
||||
"Cancel my participation request\u2026": "Cancel my participation request\u2026",
|
||||
"Cancel my participation\u2026": "Cancel my participation\u2026",
|
||||
"Cancel participation": "Cancel participation",
|
||||
"Cancel update":"Cancel update",
|
||||
"Cancelled": "Cancelled",
|
||||
"Cancelled: Won't happen": "Cancelled: Won't happen",
|
||||
"Categories": "Categories",
|
||||
@@ -303,6 +304,7 @@
|
||||
"Create token": "Create token",
|
||||
"Created by {name}": "Created by {name}",
|
||||
"Created by {username}": "Created by {username}",
|
||||
"Creation date":"Creation date",
|
||||
"Current identity has been changed to {identityName} in order to manage this event.": "Current identity has been changed to {identityName} in order to manage this event.",
|
||||
"Current page": "Current page",
|
||||
"Custom": "Custom",
|
||||
@@ -338,6 +340,7 @@
|
||||
"Delete events": "Delete events",
|
||||
"Delete everything": "Delete everything",
|
||||
"Delete feed tokens": "Delete feed tokens",
|
||||
"Delete invitation":"Delete invitation",
|
||||
"Delete group": "Delete group",
|
||||
"Delete group discussions": "Delete group discussions",
|
||||
"Delete group posts": "Delete group posts",
|
||||
@@ -385,6 +388,7 @@
|
||||
"Due on": "Due on",
|
||||
"Duplicate": "Duplicate",
|
||||
"Edit": "Edit",
|
||||
"Edit invitation": "Edit invitation",
|
||||
"Edit post": "Edit post",
|
||||
"Edit profile {profile}": "Edit profile {profile}",
|
||||
"Edit user email": "Edit user email",
|
||||
@@ -524,6 +528,7 @@
|
||||
"Google Meet": "Google Meet",
|
||||
"Group": "Group",
|
||||
"Group Followers": "Group Followers",
|
||||
"Group invitations": "Group invitations",
|
||||
"Group Members": "Group Members",
|
||||
"Group URL": "Group URL",
|
||||
"Group activity": "Group activity",
|
||||
@@ -616,6 +621,8 @@
|
||||
"Integrate this event with 3rd-party tools and show metadata for the event.": "Integrate this event with 3rd-party tools and show metadata for the event.",
|
||||
"Interact": "Interact",
|
||||
"Interact with a remote content": "Interact with a remote content",
|
||||
"Invitation links": "Invitation links",
|
||||
"Invitations": "Invitations",
|
||||
"Invite a new member": "Invite a new member",
|
||||
"Invite member": "Invite member",
|
||||
"Invited": "Invited",
|
||||
@@ -742,6 +749,7 @@
|
||||
"New discussion": "New discussion",
|
||||
"New email": "New email",
|
||||
"New folder": "New folder",
|
||||
"New invitation": "New invitation",
|
||||
"New link": "New link",
|
||||
"New members": "New members",
|
||||
"New note": "New note",
|
||||
@@ -1305,6 +1313,7 @@
|
||||
"Timezone detected as {timezone}.": "Timezone detected as {timezone}.",
|
||||
"Timezone parameters": "Timezone parameters",
|
||||
"Title": "Title",
|
||||
"Token":"Token",
|
||||
"To activate more notifications, head over to the notification settings.": "To activate more notifications, head over to the notification settings.",
|
||||
"To confirm, type your event title \"{eventTitle}\"": "To confirm, type your event title \"{eventTitle}\"",
|
||||
"To confirm, type your identity username \"{preferredUsername}\"": "To confirm, type your identity username \"{preferredUsername}\"",
|
||||
@@ -1365,6 +1374,7 @@
|
||||
"Update group discussions": "Update group discussions",
|
||||
"Update group posts": "Update group posts",
|
||||
"Update group resources": "Update group resources",
|
||||
"Update invitation":"Update invitation",
|
||||
"Update my event": "Update my event",
|
||||
"Update my profile": "Update my profile",
|
||||
"Update post": "Update post",
|
||||
|
||||
@@ -1718,5 +1718,15 @@
|
||||
"{username} was invited to {group}": "{username} a \u00e9t\u00e9 invit\u00e9 \u00e0 {group}",
|
||||
"{user}'s follow request was accepted": "La demande de suivi de {user} a \u00e9t\u00e9 accept\u00e9e",
|
||||
"{user}'s follow request was rejected": "La demande de suivi de {user} a \u00e9t\u00e9 rejet\u00e9e",
|
||||
"\u00a9 The OpenStreetMap Contributors": "\u00a9 Les Contributeur\u00b7ices OpenStreetMap"
|
||||
"\u00a9 The OpenStreetMap Contributors": "\u00a9 Les Contributeur\u00b7ices OpenStreetMap",
|
||||
"Cancel update":"Annuler la mise à jour",
|
||||
"Creation date":"Date de création",
|
||||
"Delete invitation":"Supprimer l'invitation",
|
||||
"Edit invitation": "Modifier l'invitation",
|
||||
"Group invitations":"Invitations de groupe",
|
||||
"Invitation links": "Liens d'invitation",
|
||||
"Invitations" : "Invitations",
|
||||
"New invitation": "Nouvelle invitation",
|
||||
"Token": "Jeton",
|
||||
"Update invitation" : "Mettre à jour l'invitation"
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ export enum GroupsRouteName {
|
||||
GROUP_PUBLIC_SETTINGS = "GROUP_PUBLIC_SETTINGS",
|
||||
GROUP_MEMBERS_SETTINGS = "GROUP_MEMBERS_SETTINGS",
|
||||
GROUP_FOLLOWERS_SETTINGS = "GROUP_FOLLOWERS_SETTINGS",
|
||||
GROUP_INVITATIONS_SETTINGS = "GROUP_INVITATIONS_SETTINGS",
|
||||
RESOURCES = "RESOURCES",
|
||||
RESOURCE_FOLDER_ROOT = "RESOURCE_FOLDER_ROOT",
|
||||
RESOURCE_FOLDER = "RESOURCE_FOLDER",
|
||||
@@ -96,6 +97,14 @@ export const groupsRoutes: RouteRecordRaw[] = [
|
||||
props: true,
|
||||
meta: { announcer: { skip: true } },
|
||||
},
|
||||
{
|
||||
path: "invitations",
|
||||
name: GroupsRouteName.GROUP_INVITATIONS_SETTINGS,
|
||||
component: (): Promise<any> =>
|
||||
import("../views/Group/GroupInvitations.vue"),
|
||||
props: true,
|
||||
meta: { announcer: { skip: true } },
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
4
src/types/actor/invitation.model.ts
Normal file
4
src/types/actor/invitation.model.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export interface IInvitation {
|
||||
label: string;
|
||||
token: string;
|
||||
}
|
||||
260
src/views/Group/GroupInvitations.vue
Normal file
260
src/views/Group/GroupInvitations.vue
Normal file
@@ -0,0 +1,260 @@
|
||||
<template>
|
||||
<div v-if="groupLoading" class="relative min-h-24">
|
||||
<o-loading :fullPage="false" :active="true" />
|
||||
</div>
|
||||
<div v-else-if="groupError">
|
||||
<o-notification type="danger" variant="danger">{{
|
||||
groupError.message
|
||||
}}</o-notification>
|
||||
</div>
|
||||
<div v-else-if="group">
|
||||
<breadcrumbs-nav
|
||||
:links="[
|
||||
{
|
||||
name: RouteName.GROUP,
|
||||
params: { preferredUsername: usernameWithDomain(group) },
|
||||
text: displayName(group),
|
||||
},
|
||||
{
|
||||
name: RouteName.GROUP_SETTINGS,
|
||||
params: { preferredUsername: usernameWithDomain(group) },
|
||||
text: t('Settings'),
|
||||
},
|
||||
{
|
||||
name: RouteName.GROUP_INVITATIONS_SETTINGS,
|
||||
params: { preferredUsername: usernameWithDomain(group) },
|
||||
text: t('Group invitations'),
|
||||
},
|
||||
]"
|
||||
/>
|
||||
<section class="container mx-auto section">
|
||||
<h1>{{ t("Invitation links") }}</h1>
|
||||
<o-field groupedClass="flex-wrap" grouped>
|
||||
<o-input :placeholder="t('Label')" v-model="createInvitationLabel" />
|
||||
<o-button
|
||||
variant="primary"
|
||||
:loading="createGroupInvitationLoading"
|
||||
@click="
|
||||
createGroupInvitation({
|
||||
groupId: group.id,
|
||||
label: createInvitationLabel,
|
||||
})
|
||||
"
|
||||
>{{ t("New invitation") }}</o-button
|
||||
>
|
||||
</o-field>
|
||||
<div v-if="groupInvitationsLoading" class="relative min-h-24">
|
||||
<o-loading :fullPage="false" :active="groupInvitationsLoading" />
|
||||
</div>
|
||||
<div v-else-if="groupInvitationsError">
|
||||
<o-notification type="danger" variant="danger">{{
|
||||
groupInvitationsError?.message
|
||||
}}</o-notification>
|
||||
</div>
|
||||
<div v-else-if="groupInvitationsResult">
|
||||
<o-table :data="groupInvitationsResult.listInvitations">
|
||||
<o-table-column
|
||||
field="label"
|
||||
:label="t('Label')"
|
||||
sortable
|
||||
v-slot="props"
|
||||
>
|
||||
<o-input
|
||||
v-if="updateInvitationToken == props.row.token"
|
||||
:placeholder="t('Label')"
|
||||
v-model="updateInvitationLabel"
|
||||
/>
|
||||
<span v-else>{{ props.row.label }}</span>
|
||||
</o-table-column>
|
||||
<o-table-column field="token" :label="t('Token')" sortable />
|
||||
<o-table-column field="url" :label="t('URL')" sortable />
|
||||
<o-table-column
|
||||
field="creationDate"
|
||||
:label="t('Creation date')"
|
||||
sortable
|
||||
/>
|
||||
<o-table-column
|
||||
field="token"
|
||||
:label="t('Actions')"
|
||||
sortable
|
||||
v-slot="props"
|
||||
>
|
||||
<div class="flex gap-1 flex-wrap m-1">
|
||||
<o-button
|
||||
class="grow"
|
||||
variant="primary"
|
||||
v-if="updateInvitationToken != props.row.token"
|
||||
@click="
|
||||
actionEditGroupInvitation(props.row.token, props.row.label)
|
||||
"
|
||||
:loading="updateGroupInvitationLoading"
|
||||
>{{ t("Edit invitation") }}</o-button
|
||||
>
|
||||
<o-button
|
||||
class="grow"
|
||||
variant="success"
|
||||
v-if="updateInvitationToken == props.row.token"
|
||||
@click="actionUpdateGroupInvitation()"
|
||||
:loading="updateGroupInvitationLoading"
|
||||
>{{ t("Update invitation") }}</o-button
|
||||
>
|
||||
<o-button
|
||||
class="grow"
|
||||
variant="warning"
|
||||
v-if="updateInvitationToken == props.row.token"
|
||||
@click="actionCancelEditGroupInvitation()"
|
||||
:loading="updateGroupInvitationLoading"
|
||||
>{{ t("Cancel update") }}</o-button
|
||||
>
|
||||
<o-button
|
||||
class="grow"
|
||||
variant="danger"
|
||||
v-if="updateInvitationToken != props.row.token"
|
||||
@click="actionDeleteGroupInvitation(props.row.token)"
|
||||
:loading="deleteGroupInvitationLoading"
|
||||
>{{ t("Delete invitation") }}</o-button
|
||||
>
|
||||
</div>
|
||||
</o-table-column>
|
||||
</o-table>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import RouteName from "@/router/name";
|
||||
import {
|
||||
GROUP_INVITATIONS_LIST,
|
||||
GROUP_INVITATIONS_DELETE,
|
||||
GROUP_INVITATIONS_CREATE,
|
||||
GROUP_INVITATIONS_UPDATE,
|
||||
} from "@/graphql/invitations";
|
||||
import { usernameWithDomain, displayName, IGroup } from "@/types/actor";
|
||||
import { useHead } from "@/utils/head";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useMutation, useQuery } from "@vue/apollo-composable";
|
||||
import { computed, ref } from "vue";
|
||||
import { useGroup } from "@/composition/apollo/group";
|
||||
import { IInvitation } from "@/types/actor/invitation.model";
|
||||
|
||||
const { t } = useI18n({ useScope: "global" });
|
||||
|
||||
useHead({
|
||||
title: computed(() => t("Group invitations")),
|
||||
});
|
||||
|
||||
const props = defineProps<{ preferredUsername: string }>();
|
||||
const preferredUsername = computed(() => props.preferredUsername);
|
||||
|
||||
const {
|
||||
group,
|
||||
loading: groupLoading,
|
||||
error: groupError,
|
||||
} = useGroup(preferredUsername);
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// List invitations
|
||||
// -------------------------------------------------------------
|
||||
|
||||
const {
|
||||
result: groupInvitationsResult,
|
||||
loading: groupInvitationsLoading,
|
||||
error: groupInvitationsError,
|
||||
refetch: groupInvitationsRefetch,
|
||||
} = useQuery<{ listInvitations: IInvitation }>(GROUP_INVITATIONS_LIST, () => ({
|
||||
groupId: group.value?.id,
|
||||
}));
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// Create invitation
|
||||
// -------------------------------------------------------------
|
||||
|
||||
const createInvitationLabel = ref<string>("");
|
||||
|
||||
const {
|
||||
mutate: createGroupInvitation,
|
||||
onDone: onCreateGroupInvitationDone,
|
||||
onError: onCreateGroupInvitationError,
|
||||
loading: createGroupInvitationLoading,
|
||||
} = useMutation(GROUP_INVITATIONS_CREATE);
|
||||
|
||||
onCreateGroupInvitationDone(() => {
|
||||
// TODO : pas de refetch, mise à jour du cache
|
||||
groupInvitationsRefetch();
|
||||
createInvitationLabel.value = "";
|
||||
});
|
||||
|
||||
onCreateGroupInvitationError((error) => {
|
||||
alert(error.message);
|
||||
});
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// Update invitation
|
||||
// -------------------------------------------------------------
|
||||
|
||||
const updateInvitationToken = ref<string>("");
|
||||
const updateInvitationLabel = ref<string>("");
|
||||
|
||||
const {
|
||||
mutate: updateGroupInvitation,
|
||||
onDone: onUpdateGroupInvitationDone,
|
||||
onError: onUpdateGroupInvitationError,
|
||||
loading: updateGroupInvitationLoading,
|
||||
} = useMutation(GROUP_INVITATIONS_UPDATE);
|
||||
|
||||
onUpdateGroupInvitationDone(() => {
|
||||
// TODO : pas de refetch, mise à jour du cache
|
||||
groupInvitationsRefetch();
|
||||
updateInvitationToken.value = "";
|
||||
updateInvitationLabel.value = "";
|
||||
});
|
||||
|
||||
onUpdateGroupInvitationError((error) => {
|
||||
alert(error.message);
|
||||
});
|
||||
|
||||
const actionEditGroupInvitation = (token: string, label: string) => {
|
||||
updateInvitationToken.value = token;
|
||||
updateInvitationLabel.value = label;
|
||||
};
|
||||
|
||||
const actionCancelEditGroupInvitation = () => {
|
||||
updateInvitationToken.value = "";
|
||||
};
|
||||
|
||||
const actionUpdateGroupInvitation = () => {
|
||||
updateGroupInvitation({
|
||||
groupId: group.value?.id,
|
||||
token: updateInvitationToken.value,
|
||||
label: updateInvitationLabel.value,
|
||||
});
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// Delete invitation
|
||||
// -------------------------------------------------------------
|
||||
|
||||
const {
|
||||
mutate: deleteGroupInvitation,
|
||||
onDone: deleteGroupInvitationDone,
|
||||
onError: deleteGroupInvitationError,
|
||||
loading: deleteGroupInvitationLoading,
|
||||
} = useMutation(GROUP_INVITATIONS_DELETE);
|
||||
|
||||
deleteGroupInvitationDone(() => {
|
||||
// TODO : pas de refetch, mise à jour du cache
|
||||
groupInvitationsRefetch();
|
||||
});
|
||||
|
||||
deleteGroupInvitationError((error) => {
|
||||
alert(error.message);
|
||||
});
|
||||
|
||||
const actionDeleteGroupInvitation = (token: string) => {
|
||||
deleteGroupInvitation({
|
||||
groupId: group.value?.id,
|
||||
token: token,
|
||||
});
|
||||
};
|
||||
</script>
|
||||
@@ -20,6 +20,10 @@
|
||||
:title="t('Followers')"
|
||||
:to="{ name: RouteName.GROUP_FOLLOWERS_SETTINGS }"
|
||||
/>
|
||||
<SettingMenuItem
|
||||
:title="t('Invitations')"
|
||||
:to="{ name: RouteName.GROUP_INVITATIONS_SETTINGS }"
|
||||
/>
|
||||
</SettingMenuSection>
|
||||
</ul>
|
||||
</aside>
|
||||
|
||||
Reference in New Issue
Block a user