fix: Accept invite in admin (#7393)
* fix: Accept invite in admin * fix: Accept invite in admin * minor fix
This commit is contained in:
1 parent
bb5872de48
commit
4ee47cf9b1
13 files changed
+210
-57
No files matched your search
@@ -21,3 +21,15 @@ export const useLogout = (options?: UseMutationOptions<void, Error>) => {
|
|||||||
...options,
|
...options,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const useCreateAuthUser = (
|
||||||
|
options?: UseMutationOptions<{ token: string }, Error, EmailPassReq>
|
||||||
|
) => {
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (payload) => sdk.auth.create("admin", "emailpass", payload),
|
||||||
|
onSuccess: async (data, variables, context) => {
|
||||||
|
options?.onSuccess?.(data, variables, context)
|
||||||
|
},
|
||||||
|
...options,
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -5,15 +5,15 @@ import {
|
|||||||
useMutation,
|
useMutation,
|
||||||
useQuery,
|
useQuery,
|
||||||
} from "@tanstack/react-query"
|
} from "@tanstack/react-query"
|
||||||
import { client } from "../../lib/client"
|
import { sdk } from "../../lib/client"
|
||||||
import { queryClient } from "../../lib/medusa"
|
import { queryClient } from "../../lib/medusa"
|
||||||
import { queryKeysFactory } from "../../lib/query-key-factory"
|
import { queryKeysFactory } from "../../lib/query-key-factory"
|
||||||
import { CreateInviteReq } from "../../types/api-payloads"
|
|
||||||
import {
|
import {
|
||||||
InviteDeleteRes,
|
AdminInviteResponse,
|
||||||
InviteListRes,
|
DeleteResponse,
|
||||||
InviteRes,
|
HttpTypes,
|
||||||
} from "../../types/api-responses"
|
PaginatedResponse,
|
||||||
|
} from "@medusajs/types"
|
||||||
|
|
||||||
const INVITES_QUERY_KEY = "invites" as const
|
const INVITES_QUERY_KEY = "invites" as const
|
||||||
const invitesQueryKeys = queryKeysFactory(INVITES_QUERY_KEY)
|
const invitesQueryKeys = queryKeysFactory(INVITES_QUERY_KEY)
|
||||||
@@ -21,13 +21,18 @@ const invitesQueryKeys = queryKeysFactory(INVITES_QUERY_KEY)
|
|||||||
export const useInvite = (
|
export const useInvite = (
|
||||||
id: string,
|
id: string,
|
||||||
options?: Omit<
|
options?: Omit<
|
||||||
UseQueryOptions<InviteRes, Error, InviteRes, QueryKey>,
|
UseQueryOptions<
|
||||||
|
{ invite: HttpTypes.AdminInviteResponse },
|
||||||
|
Error,
|
||||||
|
{ invite: HttpTypes.AdminInviteResponse },
|
||||||
|
QueryKey
|
||||||
|
>,
|
||||||
"queryFn" | "queryKey"
|
"queryFn" | "queryKey"
|
||||||
>
|
>
|
||||||
) => {
|
) => {
|
||||||
const { data, ...rest } = useQuery({
|
const { data, ...rest } = useQuery({
|
||||||
queryKey: invitesQueryKeys.detail(id),
|
queryKey: invitesQueryKeys.detail(id),
|
||||||
queryFn: async () => client.invites.retrieve(id),
|
queryFn: async () => sdk.admin.invites.retrieve(id),
|
||||||
...options,
|
...options,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -37,12 +42,17 @@ export const useInvite = (
|
|||||||
export const useInvites = (
|
export const useInvites = (
|
||||||
query?: Record<string, any>,
|
query?: Record<string, any>,
|
||||||
options?: Omit<
|
options?: Omit<
|
||||||
UseQueryOptions<InviteListRes, Error, InviteListRes, QueryKey>,
|
UseQueryOptions<
|
||||||
|
PaginatedResponse<{ invites: HttpTypes.AdminInviteResponse[] }>,
|
||||||
|
Error,
|
||||||
|
PaginatedResponse<{ invites: HttpTypes.AdminInviteResponse[] }>,
|
||||||
|
QueryKey
|
||||||
|
>,
|
||||||
"queryFn" | "queryKey"
|
"queryFn" | "queryKey"
|
||||||
>
|
>
|
||||||
) => {
|
) => {
|
||||||
const { data, ...rest } = useQuery({
|
const { data, ...rest } = useQuery({
|
||||||
queryFn: () => client.invites.list(query),
|
queryFn: () => sdk.admin.invites.list(query),
|
||||||
queryKey: invitesQueryKeys.list(query),
|
queryKey: invitesQueryKeys.list(query),
|
||||||
...options,
|
...options,
|
||||||
})
|
})
|
||||||
@@ -51,10 +61,14 @@ export const useInvites = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const useCreateInvite = (
|
export const useCreateInvite = (
|
||||||
options?: UseMutationOptions<InviteRes, Error, CreateInviteReq>
|
options?: UseMutationOptions<
|
||||||
|
{ invite: AdminInviteResponse },
|
||||||
|
Error,
|
||||||
|
HttpTypes.AdminCreateInvite
|
||||||
|
>
|
||||||
) => {
|
) => {
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: (payload) => client.invites.create(payload),
|
mutationFn: (payload) => sdk.admin.invites.create(payload),
|
||||||
onSuccess: (data, variables, context) => {
|
onSuccess: (data, variables, context) => {
|
||||||
queryClient.invalidateQueries({ queryKey: invitesQueryKeys.lists() })
|
queryClient.invalidateQueries({ queryKey: invitesQueryKeys.lists() })
|
||||||
options?.onSuccess?.(data, variables, context)
|
options?.onSuccess?.(data, variables, context)
|
||||||
@@ -65,10 +79,10 @@ export const useCreateInvite = (
|
|||||||
|
|
||||||
export const useResendInvite = (
|
export const useResendInvite = (
|
||||||
id: string,
|
id: string,
|
||||||
options?: UseMutationOptions<InviteRes, Error, void>
|
options?: UseMutationOptions<{ invite: AdminInviteResponse }, Error, void>
|
||||||
) => {
|
) => {
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: () => client.invites.resend(id),
|
mutationFn: () => sdk.admin.invites.resend(id),
|
||||||
onSuccess: (data, variables, context) => {
|
onSuccess: (data, variables, context) => {
|
||||||
queryClient.invalidateQueries({ queryKey: invitesQueryKeys.lists() })
|
queryClient.invalidateQueries({ queryKey: invitesQueryKeys.lists() })
|
||||||
queryClient.invalidateQueries({ queryKey: invitesQueryKeys.detail(id) })
|
queryClient.invalidateQueries({ queryKey: invitesQueryKeys.detail(id) })
|
||||||
@@ -80,10 +94,10 @@ export const useResendInvite = (
|
|||||||
|
|
||||||
export const useDeleteInvite = (
|
export const useDeleteInvite = (
|
||||||
id: string,
|
id: string,
|
||||||
options?: UseMutationOptions<InviteDeleteRes, Error, void>
|
options?: UseMutationOptions<DeleteResponse<"invite">, Error, void>
|
||||||
) => {
|
) => {
|
||||||
return useMutation({
|
return useMutation({
|
||||||
mutationFn: () => client.invites.delete(id),
|
mutationFn: () => sdk.admin.invites.delete(id),
|
||||||
onSuccess: (data, variables, context) => {
|
onSuccess: (data, variables, context) => {
|
||||||
queryClient.invalidateQueries({ queryKey: invitesQueryKeys.lists() })
|
queryClient.invalidateQueries({ queryKey: invitesQueryKeys.lists() })
|
||||||
queryClient.invalidateQueries({ queryKey: invitesQueryKeys.detail(id) })
|
queryClient.invalidateQueries({ queryKey: invitesQueryKeys.detail(id) })
|
||||||
@@ -92,3 +106,30 @@ export const useDeleteInvite = (
|
|||||||
...options,
|
...options,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const useAcceptInvite = (
|
||||||
|
inviteToken: string,
|
||||||
|
options?: UseMutationOptions<
|
||||||
|
{ user: HttpTypes.AdminUserResponse },
|
||||||
|
Error,
|
||||||
|
HttpTypes.AdminAcceptInvite & { auth_token: string }
|
||||||
|
>
|
||||||
|
) => {
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (payload) => {
|
||||||
|
const { auth_token, ...rest } = payload
|
||||||
|
|
||||||
|
return sdk.admin.invites.accept(
|
||||||
|
{ invite_token: inviteToken, ...rest },
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
Authorization: `Bearer ${auth_token}`,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
|
onSuccess: (data, variables, context) => {
|
||||||
|
options?.onSuccess?.(data, variables, context)
|
||||||
|
},
|
||||||
|
...options,
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
import { useMutation } from "@tanstack/react-query"
|
|
||||||
import { medusa } from "../medusa"
|
|
||||||
import { AcceptInviteInput, CreateAuthUserInput } from "./types/auth"
|
|
||||||
|
|
||||||
export const useV2CreateAuthUser = (provider = "emailpass") => {
|
|
||||||
// TODO: Migrate type to work for other providers, e.g. Google
|
|
||||||
return useMutation((args: CreateAuthUserInput) =>
|
|
||||||
medusa.client.request("POST", `/auth/admin/${provider}`, args)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useV2AcceptInvite = (inviteToken: string) => {
|
|
||||||
return useMutation((input: AcceptInviteInput) =>
|
|
||||||
medusa.client.request(
|
|
||||||
"POST",
|
|
||||||
`/admin/invites/accept?token=${inviteToken}`,
|
|
||||||
input.payload,
|
|
||||||
{},
|
|
||||||
{
|
|
||||||
Authorization: `Bearer ${input.token}`,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -5,7 +5,6 @@ import { AnimatePresence, motion } from "framer-motion"
|
|||||||
import { Trans, useTranslation } from "react-i18next"
|
import { Trans, useTranslation } from "react-i18next"
|
||||||
import { Link, useSearchParams } from "react-router-dom"
|
import { Link, useSearchParams } from "react-router-dom"
|
||||||
import * as z from "zod"
|
import * as z from "zod"
|
||||||
|
|
||||||
import i18n from "i18next"
|
import i18n from "i18next"
|
||||||
import { useState } from "react"
|
import { useState } from "react"
|
||||||
import { useForm } from "react-hook-form"
|
import { useForm } from "react-hook-form"
|
||||||
@@ -13,7 +12,8 @@ import { decodeToken } from "react-jwt"
|
|||||||
import { Form } from "../../components/common/form"
|
import { Form } from "../../components/common/form"
|
||||||
import { LogoBox } from "../../components/common/logo-box"
|
import { LogoBox } from "../../components/common/logo-box"
|
||||||
import { isAxiosError } from "../../lib/is-axios-error"
|
import { isAxiosError } from "../../lib/is-axios-error"
|
||||||
import { useV2AcceptInvite, useV2CreateAuthUser } from "../../lib/api-v2"
|
import { useAcceptInvite } from "../../hooks/api/invites"
|
||||||
|
import { useCreateAuthUser } from "../../hooks/api/auth"
|
||||||
|
|
||||||
const CreateAccountSchema = z
|
const CreateAccountSchema = z
|
||||||
.object({
|
.object({
|
||||||
@@ -205,10 +205,10 @@ const CreateView = ({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const { mutateAsync: createAuthUser, isPending: isCreatingAuthUser } =
|
const { mutateAsync: createAuthUser, isPending: isCreatingAuthUser } =
|
||||||
useV2CreateAuthUser()
|
useCreateAuthUser()
|
||||||
|
|
||||||
const { mutateAsync: acceptInvite, isPending: isAcceptingInvite } =
|
const { mutateAsync: acceptInvite, isPending: isAcceptingInvite } =
|
||||||
useV2AcceptInvite(token)
|
useAcceptInvite(token)
|
||||||
|
|
||||||
const handleSubmit = form.handleSubmit(async (data) => {
|
const handleSubmit = form.handleSubmit(async (data) => {
|
||||||
try {
|
try {
|
||||||
@@ -224,8 +224,8 @@ const CreateView = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
await acceptInvite({
|
await acceptInvite({
|
||||||
payload: invitePayload,
|
...invitePayload,
|
||||||
token: authToken,
|
auth_token: authToken,
|
||||||
})
|
})
|
||||||
onSuccess()
|
onSuccess()
|
||||||
toast.success(t("general.success"), {
|
toast.success(t("general.success"), {
|
||||||
|
|||||||
@@ -80,4 +80,76 @@ export class Admin {
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public invites = {
|
||||||
|
accept: async (
|
||||||
|
input: HttpTypes.AdminAcceptInvite & { invite_token: string },
|
||||||
|
query?: SelectParams,
|
||||||
|
headers?: ClientHeaders
|
||||||
|
) => {
|
||||||
|
const { invite_token, ...rest } = input
|
||||||
|
return this.client.fetch<{ user: HttpTypes.AdminUserResponse }>(
|
||||||
|
`/admin/invites/accept?token=${input.invite_token}`,
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
headers,
|
||||||
|
body: rest,
|
||||||
|
query,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
|
create: async (
|
||||||
|
body: HttpTypes.AdminCreateInvite,
|
||||||
|
query?: SelectParams,
|
||||||
|
headers?: ClientHeaders
|
||||||
|
) => {
|
||||||
|
return this.client.fetch<{ invite: HttpTypes.AdminInviteResponse }>(
|
||||||
|
`/admin/invites`,
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
headers,
|
||||||
|
body,
|
||||||
|
query,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
|
retrieve: async (
|
||||||
|
id: string,
|
||||||
|
query?: SelectParams,
|
||||||
|
headers?: ClientHeaders
|
||||||
|
) => {
|
||||||
|
return this.client.fetch<{ invite: HttpTypes.AdminInviteResponse }>(
|
||||||
|
`/admin/invites/${id}`,
|
||||||
|
{
|
||||||
|
headers,
|
||||||
|
query,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
|
list: async (queryParams?: FindParams, headers?: ClientHeaders) => {
|
||||||
|
return this.client.fetch<
|
||||||
|
PaginatedResponse<{ invites: HttpTypes.AdminInviteResponse[] }>
|
||||||
|
>(`/admin/invites`, {
|
||||||
|
headers,
|
||||||
|
query: queryParams,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
resend: async (id: string, headers?: ClientHeaders) => {
|
||||||
|
return this.client.fetch<{ invite: HttpTypes.AdminInviteResponse }>(
|
||||||
|
`/admin/invites/${id}/resend`,
|
||||||
|
{
|
||||||
|
headers,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
|
delete: async (id: string, headers?: ClientHeaders) => {
|
||||||
|
return this.client.fetch<DeleteResponse<"invite">>(
|
||||||
|
`/admin/invites/${id}`,
|
||||||
|
{
|
||||||
|
method: "DELETE",
|
||||||
|
headers,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -10,7 +10,7 @@ export class Auth {
|
|||||||
this.config = config
|
this.config = config
|
||||||
}
|
}
|
||||||
|
|
||||||
login = async (
|
public login = async (
|
||||||
scope: "admin" | "store",
|
scope: "admin" | "store",
|
||||||
method: "emailpass",
|
method: "emailpass",
|
||||||
payload: { email: string; password: string }
|
payload: { email: string; password: string }
|
||||||
@@ -43,4 +43,15 @@ export class Auth {
|
|||||||
|
|
||||||
this.client.clearToken()
|
this.client.clearToken()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
create = async (
|
||||||
|
scope: "admin" | "store",
|
||||||
|
method: "emailpass",
|
||||||
|
payload: { email: string; password: string }
|
||||||
|
): Promise<{ token: string }> => {
|
||||||
|
return await this.client.fetch(`/auth/${scope}/${method}`, {
|
||||||
|
method: "POST",
|
||||||
|
body: payload,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -161,8 +161,10 @@ export class Client {
|
|||||||
if (input instanceof URL || typeof input === "string") {
|
if (input instanceof URL || typeof input === "string") {
|
||||||
normalizedInput = new URL(input, this.config.baseUrl)
|
normalizedInput = new URL(input, this.config.baseUrl)
|
||||||
if (init?.query) {
|
if (init?.query) {
|
||||||
const existing = qs.parse(normalizedInput.search)
|
const params = Object.fromEntries(
|
||||||
const stringifiedQuery = qs.stringify({ existing, ...init.query })
|
normalizedInput.searchParams.entries()
|
||||||
|
)
|
||||||
|
const stringifiedQuery = qs.stringify({ ...params, ...init.query })
|
||||||
normalizedInput.search = stringifiedQuery
|
normalizedInput.search = stringifiedQuery
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,22 @@
|
|||||||
export * from "./api-key"
|
export * from "./api-key"
|
||||||
export * from "./campaign"
|
export * from "./campaign"
|
||||||
|
export * from "./cart"
|
||||||
|
export * from "./collection"
|
||||||
|
export * from "./common"
|
||||||
export * from "./customer"
|
export * from "./customer"
|
||||||
export * from "./fulfillment"
|
export * from "./fulfillment"
|
||||||
export * from "./inventory"
|
export * from "./inventory"
|
||||||
|
export * from "./invite"
|
||||||
export * from "./order"
|
export * from "./order"
|
||||||
|
export * from "./payment"
|
||||||
export * from "./pricing"
|
export * from "./pricing"
|
||||||
|
export * from "./product"
|
||||||
export * from "./product-category"
|
export * from "./product-category"
|
||||||
export * from "./promotion"
|
export * from "./promotion"
|
||||||
|
export * from "./region"
|
||||||
|
export * from "./reservation"
|
||||||
export * from "./sales-channel"
|
export * from "./sales-channel"
|
||||||
export * from "./stock-locations"
|
export * from "./stock-locations"
|
||||||
export * from "./tax"
|
export * from "./tax"
|
||||||
export * from "./product-category"
|
export * from "./user"
|
||||||
export * from "./reservation"
|
|
||||||
export * from "./region"
|
|
||||||
export * from "./product"
|
|
||||||
export * from "./cart"
|
|
||||||
export * from "./payment"
|
|
||||||
export * from "./collection"
|
|
||||||
export * from "./common"
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
export type AdminAcceptInvite = {
|
||||||
|
first_name: string
|
||||||
|
last_name: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type AdminCreateInvite = {
|
||||||
|
email: string
|
||||||
|
metadata?: Record<string, unknown>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type AdminInviteResponse = {
|
||||||
|
id: string
|
||||||
|
email: string
|
||||||
|
accepted: boolean
|
||||||
|
token: string
|
||||||
|
expires_at?: Date
|
||||||
|
metadata?: Record<string, unknown>
|
||||||
|
created_at?: Date
|
||||||
|
updated_at?: Date
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export * from "./admin"
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
import { BaseUserResponse } from "./common"
|
||||||
|
|
||||||
|
export type AdminUserResponse = BaseUserResponse
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
export type BaseUserResponse = {
|
||||||
|
id: string
|
||||||
|
email: string
|
||||||
|
first_name: string | null
|
||||||
|
last_name: string | null
|
||||||
|
avatar_url: string | null
|
||||||
|
metadata: Record<string, unknown> | null
|
||||||
|
created_at: Date
|
||||||
|
updated_at: Date
|
||||||
|
deleted_at: Date | null
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
export * from "./admin";
|
||||||
|
|
||||||
Reference in new issue
Block a user