feat: introduce updated mutation system and team.vue rewrite
This commit is contained in:
committed by
liyasthomas
parent
7bb32ecf7e
commit
fb4aab875d
@@ -14,7 +14,7 @@
|
|||||||
:key="`member-${index}`"
|
:key="`member-${index}`"
|
||||||
v-tippy="{ theme: 'tooltip' }"
|
v-tippy="{ theme: 'tooltip' }"
|
||||||
:title="member.user.displayName"
|
:title="member.user.displayName"
|
||||||
:src="member.user.photoURL"
|
:src="member.user.photoURL || undefined"
|
||||||
:alt="member.user.displayName"
|
:alt="member.user.displayName"
|
||||||
class="rounded-full h-5 ring-primary ring-2 w-5 inline-block"
|
class="rounded-full h-5 ring-primary ring-2 w-5 inline-block"
|
||||||
/>
|
/>
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
<SmartItem
|
<SmartItem
|
||||||
v-if="team.myRole === 'OWNER'"
|
v-if="team.myRole === 'OWNER'"
|
||||||
svg="edit"
|
svg="edit"
|
||||||
:label="$t('action.edit')"
|
:label="$t('action.edit').toString()"
|
||||||
@click.native="
|
@click.native="
|
||||||
() => {
|
() => {
|
||||||
$emit('edit-team')
|
$emit('edit-team')
|
||||||
@@ -45,7 +45,7 @@
|
|||||||
v-if="team.myRole === 'OWNER'"
|
v-if="team.myRole === 'OWNER'"
|
||||||
svg="trash-2"
|
svg="trash-2"
|
||||||
color="red"
|
color="red"
|
||||||
:label="$t('action.delete')"
|
:label="$t('action.delete').toString()"
|
||||||
@click.native="
|
@click.native="
|
||||||
() => {
|
() => {
|
||||||
deleteTeam()
|
deleteTeam()
|
||||||
@@ -56,7 +56,7 @@
|
|||||||
<SmartItem
|
<SmartItem
|
||||||
v-if="!(team.myRole === 'OWNER' && team.ownersCount == 1)"
|
v-if="!(team.myRole === 'OWNER' && team.ownersCount == 1)"
|
||||||
svg="trash"
|
svg="trash"
|
||||||
:label="$t('team.exit')"
|
:label="$t('team.exit').toString()"
|
||||||
@click.native="
|
@click.native="
|
||||||
() => {
|
() => {
|
||||||
exitTeam()
|
exitTeam()
|
||||||
@@ -69,49 +69,79 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup lang="ts">
|
||||||
import { defineComponent } from "@nuxtjs/composition-api"
|
import { useContext } from "@nuxtjs/composition-api"
|
||||||
import * as teamUtils from "~/helpers/teams/utils"
|
import { pipe } from "fp-ts/function"
|
||||||
|
import * as TE from "fp-ts/TaskEither"
|
||||||
|
import {
|
||||||
|
deleteTeam as backendDeleteTeam,
|
||||||
|
leaveTeam,
|
||||||
|
} from "~/helpers/backend/mutations/Team"
|
||||||
|
import { TeamMemberRole } from "~/helpers/backend/types/TeamMemberRole"
|
||||||
|
|
||||||
export default defineComponent({
|
const props = defineProps<{
|
||||||
props: {
|
team: {
|
||||||
team: { type: Object, default: () => {} },
|
name: string
|
||||||
teamID: { type: String, default: null },
|
myRole: TeamMemberRole
|
||||||
},
|
ownersCount: number
|
||||||
methods: {
|
members: Array<{
|
||||||
deleteTeam() {
|
user: {
|
||||||
if (!confirm(this.$t("confirm.remove_team"))) return
|
displayName: string
|
||||||
// Call to the graphql mutation
|
photoURL: string | null
|
||||||
teamUtils
|
}
|
||||||
.deleteTeam(this.$apollo, this.teamID)
|
}>
|
||||||
.then(() => {
|
}
|
||||||
this.$toast.success(this.$t("team.deleted"), {
|
teamID: string
|
||||||
icon: "done",
|
}>()
|
||||||
})
|
|
||||||
|
const {
|
||||||
|
app: { i18n },
|
||||||
|
$toast,
|
||||||
|
} = useContext()
|
||||||
|
|
||||||
|
const $t = i18n.t.bind(i18n)
|
||||||
|
|
||||||
|
const deleteTeam = () => {
|
||||||
|
if (!confirm($t("confirm.remove_team").toString())) return
|
||||||
|
|
||||||
|
pipe(
|
||||||
|
backendDeleteTeam(props.teamID),
|
||||||
|
TE.match(
|
||||||
|
(err) => {
|
||||||
|
// TODO: Better errors ? We know the possible errors now
|
||||||
|
$toast.error($t("error.something_went_wrong").toString(), {
|
||||||
|
icon: "error_outline",
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
console.error(err)
|
||||||
this.$toast.error(this.$t("error.something_went_wrong"), {
|
},
|
||||||
icon: "error_outline",
|
() => {
|
||||||
})
|
$toast.success($t("team.deleted").toString(), {
|
||||||
console.error(e)
|
icon: "done",
|
||||||
})
|
})
|
||||||
},
|
}
|
||||||
exitTeam() {
|
)
|
||||||
if (!confirm("Are you sure you want to exit this team?")) return
|
)() // Tasks (and TEs) are lazy, so call the function returned
|
||||||
teamUtils
|
}
|
||||||
.exitTeam(this.$apollo, this.teamID)
|
|
||||||
.then(() => {
|
const exitTeam = () => {
|
||||||
this.$toast.success(this.$t("team.left"), {
|
if (!confirm("Are you sure you want to exit this team?")) return
|
||||||
icon: "done",
|
|
||||||
})
|
pipe(
|
||||||
|
leaveTeam(props.teamID),
|
||||||
|
TE.match(
|
||||||
|
(err) => {
|
||||||
|
// TODO: Better errors ?
|
||||||
|
$toast.error($t("error.something_went_wrong").toString(), {
|
||||||
|
icon: "error_outline",
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
console.error(err)
|
||||||
this.$toast.error(this.$t("error.something_went_wrong"), {
|
},
|
||||||
icon: "error_outline",
|
() => {
|
||||||
})
|
$toast.success($t("team.left").toString(), {
|
||||||
console.error(e)
|
icon: "done",
|
||||||
})
|
})
|
||||||
},
|
}
|
||||||
},
|
)
|
||||||
})
|
)() // Tasks (and TEs) are lazy, so call the function returned
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ import {
|
|||||||
} from "@urql/core"
|
} from "@urql/core"
|
||||||
import { devtoolsExchange } from "@urql/devtools"
|
import { devtoolsExchange } from "@urql/devtools"
|
||||||
import * as E from "fp-ts/Either"
|
import * as E from "fp-ts/Either"
|
||||||
import { pipe } from "fp-ts/function"
|
import * as TE from "fp-ts/TaskEither"
|
||||||
|
import { pipe, constVoid } from "fp-ts/function"
|
||||||
import { subscribe } from "wonka"
|
import { subscribe } from "wonka"
|
||||||
import clone from "lodash/clone"
|
import clone from "lodash/clone"
|
||||||
import { getAuthIDToken } from "~/helpers/fb/auth"
|
import { getAuthIDToken } from "~/helpers/fb/auth"
|
||||||
@@ -49,7 +50,7 @@ export type GQLError<T extends string> =
|
|||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
type: "gql_error"
|
type: "gql_error"
|
||||||
err: T
|
error: T
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_QUERY_OPTIONS = {
|
const DEFAULT_QUERY_OPTIONS = {
|
||||||
@@ -122,7 +123,7 @@ export function useGQLQuery<
|
|||||||
(gqlErr) =>
|
(gqlErr) =>
|
||||||
<GQLError<QueryFailType>>{
|
<GQLError<QueryFailType>>{
|
||||||
type: "gql_error",
|
type: "gql_error",
|
||||||
err: gqlErr as QueryFailType,
|
error: gqlErr as QueryFailType,
|
||||||
},
|
},
|
||||||
// The right case (it was a GraphQL Error)
|
// The right case (it was a GraphQL Error)
|
||||||
(networkErr) =>
|
(networkErr) =>
|
||||||
@@ -163,3 +164,44 @@ export function useGQLQuery<
|
|||||||
}
|
}
|
||||||
| { loading: true }
|
| { loading: true }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const runMutation = <
|
||||||
|
MutationReturnType = any,
|
||||||
|
MutationFailType extends string = "",
|
||||||
|
MutationVariables extends {} = {}
|
||||||
|
>(
|
||||||
|
mutation: string | DocumentNode | TypedDocumentNode<any, MutationVariables>,
|
||||||
|
variables?: MutationVariables
|
||||||
|
): TE.TaskEither<GQLError<MutationFailType>, NonNullable<MutationReturnType>> =>
|
||||||
|
pipe(
|
||||||
|
TE.tryCatch(
|
||||||
|
() => client.mutation<MutationReturnType>(mutation, variables).toPromise(),
|
||||||
|
() => constVoid() as never // The mutation function can never fail, so this will never be called ;)
|
||||||
|
),
|
||||||
|
TE.chainEitherK((result) =>
|
||||||
|
pipe(
|
||||||
|
result.data as MutationReturnType, // If we have the result, then okay
|
||||||
|
E.fromNullable(
|
||||||
|
// Result is null
|
||||||
|
pipe(
|
||||||
|
result.error?.networkError, // Check for network error
|
||||||
|
E.fromNullable(result.error?.name), // If it is null, then it is a GQL error
|
||||||
|
E.match(
|
||||||
|
// The left case (network error was null)
|
||||||
|
(gqlErr) =>
|
||||||
|
<GQLError<MutationFailType>>{
|
||||||
|
type: "gql_error",
|
||||||
|
error: gqlErr as MutationFailType,
|
||||||
|
},
|
||||||
|
// The right case (it was a GraphQL Error)
|
||||||
|
(networkErr) =>
|
||||||
|
<GQLError<MutationFailType>>{
|
||||||
|
type: "network_error",
|
||||||
|
error: networkErr,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|||||||
33
packages/hoppscotch-app/helpers/backend/mutations/Team.ts
Normal file
33
packages/hoppscotch-app/helpers/backend/mutations/Team.ts
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import gql from "graphql-tag"
|
||||||
|
import { runMutation } from "../GQLClient"
|
||||||
|
|
||||||
|
type DeleteTeamErrors =
|
||||||
|
| "team/not_required_role"
|
||||||
|
| "team/invalid_id"
|
||||||
|
| "team/member_not_found"
|
||||||
|
|
||||||
|
type ExitTeamErrors = "team/invalid_id" | "team/member_not_found"
|
||||||
|
|
||||||
|
export const deleteTeam = (teamID: string) =>
|
||||||
|
runMutation<void, DeleteTeamErrors>(
|
||||||
|
gql`
|
||||||
|
mutation DeleteTeam($teamID: String!) {
|
||||||
|
deleteTeam(teamID: $teamID)
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
{
|
||||||
|
teamID,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
export const leaveTeam = (teamID: string) =>
|
||||||
|
runMutation<void, ExitTeamErrors>(
|
||||||
|
gql`
|
||||||
|
mutation ExitTeam($teamID: String!) {
|
||||||
|
leaveTeam(teamID: $teamID)
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
{
|
||||||
|
teamID,
|
||||||
|
}
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user