feat: invite system error states and user prompts

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

View File

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

View File

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

View File

@@ -11,21 +11,39 @@
{{ $t("team.we_sent_invite_link_description") }} {{ $t("team.we_sent_invite_link_description") }}
</p> </p>
</div> </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 <div
v-for="(invitee, index) in sendInvitesResult" v-for="(invitee, index) in sendInvitesResult"
:key="`invitee-${index}`" :key="`invitee-${index}`"
class="flex items-center"
> >
<i <p class="flex items-center">
class="material-icons mr-4" <i
:class=" class="material-icons mr-4"
invitee.status === 'error' ? 'text-red-500' : 'text-green-500' :class="
" invitee.status === 'error' ? 'text-red-500' : 'text-green-500'
> "
{{ invitee.status === "error" ? "error" : "check_circle" }} >
</i> {{
<span class="flex truncate">{{ invitee.email }}</span> 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> </div>
</div> </div>
@@ -375,18 +393,18 @@ const removeNewInvitee = (id: number) => {
newInvites.value.splice(id, 1) newInvites.value.splice(id, 1)
} }
type SendInvitesErrorType = { type SendInvitesErrorType =
email: Email | {
status: "error" email: Email
error: GQLError<CreateTeamInvitationErrors> status: "error"
} | { error: GQLError<CreateTeamInvitationErrors>
email: Email }
status: "success" | {
} email: Email
status: "success"
}
const sendInvitesResult = ref< const sendInvitesResult = ref<Array<SendInvitesErrorType>>([])
Array<SendInvitesErrorType>
>([])
const sendingInvites = ref<boolean>(false) const sendingInvites = ref<boolean>(false)
@@ -428,7 +446,7 @@ const sendInvites = async () => {
(err) => ({ (err) => ({
status: "error" as const, status: "error" as const,
email: newInvites.value[i].key as Email, email: newInvites.value[i].key as Email,
error: err error: err,
}), }),
() => ({ () => ({
status: "success" as const, status: "success" as const,
@@ -445,6 +463,23 @@ const sendInvites = async () => {
sendingInvites.value = false 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 = () => { const hideModal = () => {
sendingInvites.value = false sendingInvites.value = false
sendInvitesResult.value = [] sendInvitesResult.value = []

View File

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

View File

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

View File

@@ -4,11 +4,11 @@
v-if="invalidLink" v-if="invalidLink"
class="flex flex-1 items-center justify-center flex-col" 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"> <h1 class="heading text-center">
{{ $t("team.invalid_invite_link") }} {{ $t("team.invalid_invite_link") }}
</h1> </h1>
<p class="text-center"> <p class="text-center mt-2">
{{ $t("team.invalid_invite_link_description") }} {{ $t("team.invalid_invite_link_description") }}
</p> </p>
</div> </div>
@@ -36,8 +36,31 @@
v-if="!inviteDetails.loading && E.isLeft(inviteDetails.data)" v-if="!inviteDetails.loading && E.isLeft(inviteDetails.data)"
class="flex flex-col p-4 items-center" class="flex flex-col p-4 items-center"
> >
<i class="mb-4 material-icons">help_outline</i> <i class="mb-4 material-icons">error_outline</i>
{{ $t("error.something_went_wrong") }} <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>
<div <div
v-if="!inviteDetails.loading && E.isRight(inviteDetails.data)" 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 E from "fp-ts/Either"
import * as TE from "fp-ts/TaskEither" import * as TE from "fp-ts/TaskEither"
import { pipe } from "fp-ts/function" import { pipe } from "fp-ts/function"
import { useGQLQuery } from "~/helpers/backend/GQLClient" import { GQLError, useGQLQuery } from "~/helpers/backend/GQLClient"
import { import {
GetInviteDetailsDocument, GetInviteDetailsDocument,
GetInviteDetailsQuery, GetInviteDetailsQuery,
@@ -123,11 +146,7 @@ export default defineComponent({
}) })
onLoggedIn(() => { onLoggedIn(() => {
console.log("loog aayi")
if (typeof route.value.query.id === "string") { if (typeof route.value.query.id === "string") {
console.log("query run aayi", route.value.query.id)
inviteDetails.execute({ inviteDetails.execute({
inviteID: route.value.query.id, 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> </script>