feat: invite system error states and user prompts

This commit is contained in:
liyasthomas
2021-10-21 18:17:32 +05:30
parent c9a24a0d28
commit ddf21c17d2
6 changed files with 139 additions and 40 deletions

View File

@@ -95,12 +95,15 @@ body {
}
.material-icons {
@apply flex-shrink-0;
font-size: var(--body-line-height) !important;
width: var(--body-line-height);
overflow: hidden;
}
.svg-icons {
@apply flex-shrink-0;
height: var(--body-line-height);
width: var(--body-line-height);
}

View File

@@ -3,6 +3,7 @@
<SmartItem
svg="log-out"
:label="`${$t('auth.logout')}`"
:outline="outline"
@click.native="
() => {
$emit('confirm-logout')
@@ -24,6 +25,12 @@ import { defineComponent } from "@nuxtjs/composition-api"
import { signOutUser } from "~/helpers/fb/auth"
export default defineComponent({
props: {
outline: {
type: Boolean,
default: false,
},
},
data() {
return {
confirmLogout: false,

View File

@@ -11,21 +11,39 @@
{{ $t("team.we_sent_invite_link_description") }}
</p>
</div>
<div class="flex space-y-2 px-4 pt-8 flex-col">
<div
class="
flex
border border-dividerLight
mt-8
rounded
flex-col
space-y-6
p-4
"
>
<div
v-for="(invitee, index) in sendInvitesResult"
:key="`invitee-${index}`"
class="flex items-center"
>
<i
class="material-icons mr-4"
:class="
invitee.status === 'error' ? 'text-red-500' : 'text-green-500'
"
>
{{ invitee.status === "error" ? "error" : "check_circle" }}
</i>
<span class="flex truncate">{{ invitee.email }}</span>
<p class="flex items-center">
<i
class="material-icons mr-4"
:class="
invitee.status === 'error' ? 'text-red-500' : 'text-green-500'
"
>
{{
invitee.status === "error"
? "error_outline"
: "mark_email_read"
}}
</i>
<span class="truncate">{{ invitee.email }}</span>
</p>
<p v-if="invitee.status === 'error'" class="ml-8 text-red-500 mt-2">
{{ getErrorMessage(invitee.error) }}
</p>
</div>
</div>
</div>
@@ -375,18 +393,18 @@ const removeNewInvitee = (id: number) => {
newInvites.value.splice(id, 1)
}
type SendInvitesErrorType = {
email: Email
status: "error"
error: GQLError<CreateTeamInvitationErrors>
} | {
email: Email
status: "success"
}
type SendInvitesErrorType =
| {
email: Email
status: "error"
error: GQLError<CreateTeamInvitationErrors>
}
| {
email: Email
status: "success"
}
const sendInvitesResult = ref<
Array<SendInvitesErrorType>
>([])
const sendInvitesResult = ref<Array<SendInvitesErrorType>>([])
const sendingInvites = ref<boolean>(false)
@@ -428,7 +446,7 @@ const sendInvites = async () => {
(err) => ({
status: "error" as const,
email: newInvites.value[i].key as Email,
error: err
error: err,
}),
() => ({
status: "success" as const,
@@ -445,6 +463,23 @@ const sendInvites = async () => {
sendingInvites.value = false
}
const getErrorMessage = (error: SendInvitesErrorType) => {
if (error.type === "network_error") {
return t("error.network_error")
} else {
switch (error.error) {
case "team/invalid_id":
return t("team.invalid_id")
case "team/member_not_found":
return t("team.member_not_found")
case "team_invite/already_member":
return t("team.already_member")
case "team_invite/member_has_invite":
return t("team.member_has_invite")
}
}
}
const hideModal = () => {
sendingInvites.value = false
sendInvitesResult.value = []

View File

@@ -201,7 +201,9 @@ export const useGQLQuery = <DocType, DocVarType, DocErrorType extends string>(
(gqlErr) =>
<GQLError<DocErrorType>>{
type: "gql_error",
error: parseGQLErrorString(gqlErr ?? "") as DocErrorType,
error: parseGQLErrorString(
gqlErr ?? ""
) as DocErrorType,
},
// The right case (it was a GraphQL Error)
(networkErr) =>
@@ -244,7 +246,8 @@ export const useGQLQuery = <DocType, DocVarType, DocErrorType extends string>(
return response
}
const parseGQLErrorString = (s: string) => s.startsWith("[GraphQL] ") ? s.split("[GraphQL] ")[1] : s
const parseGQLErrorString = (s: string) =>
s.startsWith("[GraphQL] ") ? s.split("[GraphQL] ")[1] : s
export const runMutation = <
DocType,
@@ -273,13 +276,13 @@ export const runMutation = <
// Result is null
pipe(
result.error?.networkError,
E.fromNullable(result.error?.name),
E.fromNullable(result.error?.message),
E.match(
// The left case (network error was null)
(gqlErr) =>
<GQLError<DocErrors>>{
type: "gql_error",
error: gqlErr,
error: parseGQLErrorString(gqlErr ?? ""),
},
// The right case (it was a network error)
(networkErr) =>

View File

@@ -170,6 +170,7 @@
"gql_prettify_invalid_query": "Couldn't prettify an invalid query, solve query syntax errors and try again",
"incorrect_email": "Incorrect email",
"json_prettify_invalid_body": "Couldn't prettify an invalid body, solve json syntax errors and try again",
"network_error": "There seems to be a network error. Please try again.",
"network_fail": "Could not send request",
"no_duration": "No duration",
"something_went_wrong": "Something went wrong"
@@ -470,19 +471,21 @@
"websocket": "WebSocket"
},
"team": {
"already_member": "You are already a member of this team. Contact your team owner.",
"create_new": "Create new team",
"deleted": "Team deleted",
"edit": "Edit Team",
"email": "E-mail",
"email_do_not_match": "Email doesn't match with your account details. Contact your team owner.",
"exit": "Exit Team",
"exit_disabled": "Only owner cannot exit the team",
"invalid_email_format": "Email format is invalid",
"invalid_member_permission": "Please provide a valid permission to the team member",
"invalid_id": "Invalid team ID. Contact your team owner.",
"invalid_invite_link": "Invalid invite link",
"invalid_invite_link_description": "The link you followed is invalid. Contact your team owner.",
"invalid_member_permission": "Please provide a valid permission to the team member",
"invite": "Invite",
"login_to_continue": "Login to continue",
"login_to_continue_description": "You need to be logged in to join a team.",
"logout_and_try_again": "Logout and sign in with another account",
"invite_more": "Invite more",
"invite_tooltip": "Invite people to this workspace",
"invited_to_team": "{owner} invited you to join {team}",
@@ -490,6 +493,10 @@
"join_beta": "Join the beta program to access teams.",
"join_team": "Join {team}",
"left": "You left the team",
"login_to_continue": "Login to continue",
"login_to_continue_description": "You need to be logged in to join a team.",
"member_has_invite": "This email ID already has an invite. Contact your team owner.",
"member_not_found": "Member not found. Contact your team owner.",
"member_removed": "User removed",
"member_role_updated": "User roles updated",
"members": "Members",
@@ -498,6 +505,9 @@
"new_created": "New team created",
"new_name": "My New Team",
"no_access": "You do not have edit access to these collections",
"no_invite_found": "Invitation not found. Contact your team owner.",
"not_invitee": "Invite link doesn't match with your account details. Contact your team owner.",
"not_valid_viewer": "You are not a valid viewer. Contact your team owner.",
"pending_invites": "Pending invites",
"permissions": "Permissions",
"saved": "Team saved",

View File

@@ -4,11 +4,11 @@
v-if="invalidLink"
class="flex flex-1 items-center justify-center flex-col"
>
<i class="opacity-75 pb-2 material-icons">report</i>
<i class="opacity-75 pb-2 material-icons">error_outline</i>
<h1 class="heading text-center">
{{ $t("team.invalid_invite_link") }}
</h1>
<p class="text-center">
<p class="text-center mt-2">
{{ $t("team.invalid_invite_link_description") }}
</p>
</div>
@@ -36,8 +36,31 @@
v-if="!inviteDetails.loading && E.isLeft(inviteDetails.data)"
class="flex flex-col p-4 items-center"
>
<i class="mb-4 material-icons">help_outline</i>
{{ $t("error.something_went_wrong") }}
<i class="mb-4 material-icons">error_outline</i>
<p>
{{ getErrorMessage(inviteDetails.data.left.error) }}
</p>
<p
class="
p-4
items-center
mt-8
rounded
flex-col
border border-dividerLight
flex
"
>
<span class="mb-4">
{{ $t("team.logout_and_try_again") }}
</span>
<span class="flex">
<FirebaseLogout
v-if="inviteDetails.data.left.type === 'gql_error'"
outline
/>
</span>
</p>
</div>
<div
v-if="!inviteDetails.loading && E.isRight(inviteDetails.data)"
@@ -91,7 +114,7 @@ import { defineComponent, useRoute } from "@nuxtjs/composition-api"
import * as E from "fp-ts/Either"
import * as TE from "fp-ts/TaskEither"
import { pipe } from "fp-ts/function"
import { useGQLQuery } from "~/helpers/backend/GQLClient"
import { GQLError, useGQLQuery } from "~/helpers/backend/GQLClient"
import {
GetInviteDetailsDocument,
GetInviteDetailsQuery,
@@ -123,11 +146,7 @@ export default defineComponent({
})
onLoggedIn(() => {
console.log("loog aayi")
if (typeof route.value.query.id === "string") {
console.log("query run aayi", route.value.query.id)
inviteDetails.execute({
inviteID: route.value.query.id,
})
@@ -180,6 +199,28 @@ export default defineComponent({
)
)()
},
getErrorMessage(error: GQLError<GetInviteDetailsError>) {
if (error.type === "network_error") {
return this.$t("error.network_error")
} else {
switch (error) {
case "team_invite/not_valid_viewer":
return this.$t("team.not_valid_viewer")
case "team_invite/not_found":
return this.$t("team.not_found")
case "team_invite/no_invite_found":
return this.$t("team.no_invite_found")
case "team_invite/not_invitee":
return this.$t("team.not_invitee")
case "team_invite/already_member":
return this.$t("team.already_member")
case "team_invite/email_do_not_match":
return this.$t("team.email_do_not_match")
default:
return this.$t("error.something_went_wrong")
}
}
},
},
})
</script>