refactor(dashboard): refresh domains (#7087)
This commit is contained in:
@@ -280,7 +280,12 @@
|
||||
"manageInventoryLabel": "Manage inventory",
|
||||
"manageInventoryHint": "When enabled the inventory level will be regulated when orders and returns are created.",
|
||||
"allowBackordersLabel": "Allow backorders",
|
||||
"allowBackordersHint": "When enabled the variant can be sold even if the inventory level is below zero."
|
||||
"allowBackordersHint": "When enabled the variant can be sold even if the inventory level is below zero.",
|
||||
"toast": {
|
||||
"levelsBatch": "Inventory levels updated.",
|
||||
"update": "Inventory item updated successfully",
|
||||
"updateLevel": "Inventory level updated successfully"
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
@@ -1018,6 +1023,9 @@
|
||||
"languageHint": "The language you want to use in the admin dashboard. This will not change the language of your store.",
|
||||
"languagePlaceholder": "Select language",
|
||||
"usageInsightsHint": "Share usage insights and help us improve Medusa. You can read more about what we collect and how we use it in our <0>documentation</0>."
|
||||
},
|
||||
"toast": {
|
||||
"edit": "Profiles changes saved"
|
||||
}
|
||||
},
|
||||
"users": {
|
||||
@@ -1051,6 +1059,7 @@
|
||||
"manageYourStoresDetails": "Manage your store's details",
|
||||
"editStore": "Edit store",
|
||||
"defaultCurrency": "Default currency",
|
||||
"defaultRegion": "Default region",
|
||||
"swapLinkTemplate": "Swap link template",
|
||||
"paymentLinkTemplate": "Payment link template",
|
||||
"inviteLinkTemplate": "Invite link template",
|
||||
@@ -1061,6 +1070,11 @@
|
||||
"currencyAlreadyAdded": "The currency has already been added to your store.",
|
||||
"edit": {
|
||||
"header": "Edit Store"
|
||||
},
|
||||
"toast": {
|
||||
"update": "Store successfully updated",
|
||||
"currenciesUpdated": "Currencies updated successfully",
|
||||
"currenciesRemoved": "Removed currencies from the store successfully"
|
||||
}
|
||||
},
|
||||
"regions": {
|
||||
@@ -1171,7 +1185,12 @@
|
||||
"selectLocations": "Select locations that stock the item.",
|
||||
"deleteLocationWarning": "You are about to delete the location {{name}}. This action cannot be undone.",
|
||||
"removeSalesChannelsWarning_one": "You are about to remove {{count}} sales channel from the location.",
|
||||
"removeSalesChannelsWarning_other": "You are about to remove {{count}} sales channels from the location."
|
||||
"removeSalesChannelsWarning_other": "You are about to remove {{count}} sales channels from the location.",
|
||||
"toast": {
|
||||
"create": "Location created sucessfully",
|
||||
"update": "Location updated sucessfully",
|
||||
"removeChannel": "Sales channel removed sucessfully"
|
||||
}
|
||||
},
|
||||
"reservations": {
|
||||
"domain": "Reservations",
|
||||
@@ -1187,7 +1206,12 @@
|
||||
"addProducts": "Add Products",
|
||||
"editSalesChannel": "Edit sales channel",
|
||||
"productAlreadyAdded": "The product has already been added to the sales channel.",
|
||||
"deleteSalesChannelWarning": "You are about to delete the sales channel {{name}}. This action cannot be undone."
|
||||
"deleteSalesChannelWarning": "You are about to delete the sales channel {{name}}. This action cannot be undone.",
|
||||
"toast": {
|
||||
"create": "Sales channel created successfully",
|
||||
"update": "Sales channel updated successfully",
|
||||
"delete": "Sales channel deleted successfully"
|
||||
}
|
||||
},
|
||||
"apiKeyManagement": {
|
||||
"domain": {
|
||||
@@ -1279,7 +1303,10 @@
|
||||
"successAction": "Sign in to start using Medusa",
|
||||
"invalidTokenTitle": "Your invite token is invalid",
|
||||
"invalidTokenHint": "Try requesting a new invite link.",
|
||||
"passwordMismatch": "Passwords do not match"
|
||||
"passwordMismatch": "Passwords do not match",
|
||||
"toast": {
|
||||
"accepted": "Invite successfully accepted"
|
||||
}
|
||||
},
|
||||
"resetPassword": {
|
||||
"title": "Reset password",
|
||||
|
||||
@@ -167,6 +167,7 @@ export type InventoryItemRes = {
|
||||
stocked_quantity: number
|
||||
reserved_quantity: number
|
||||
location_levels?: InventoryNext.InventoryLevelDTO[]
|
||||
variant?: ProductVariantDTO | ProductVariantDTO[]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ export const AdjustInventoryDrawer = () => {
|
||||
|
||||
const {
|
||||
inventory_item: inventoryItem,
|
||||
isLoading,
|
||||
isPending: isLoading,
|
||||
isError,
|
||||
error,
|
||||
} = useInventoryItem(id!)
|
||||
|
||||
+18
-6
@@ -1,6 +1,6 @@
|
||||
import * as zod from "zod"
|
||||
|
||||
import { Button, Input, Text } from "@medusajs/ui"
|
||||
import { Button, Input, Text, toast } from "@medusajs/ui"
|
||||
import { InventoryLevelDTO, StockLocationDTO } from "@medusajs/types"
|
||||
import {
|
||||
RouteDrawer,
|
||||
@@ -61,7 +61,7 @@ export const AdjustInventoryForm = ({
|
||||
|
||||
const stockedQuantityUpdate = form.watch("stocked_quantity")
|
||||
|
||||
const { mutateAsync } = useUpdateInventoryItemLevel(
|
||||
const { mutateAsync, isPending: isLoading } = useUpdateInventoryItemLevel(
|
||||
item.id,
|
||||
level.location_id
|
||||
)
|
||||
@@ -71,9 +71,21 @@ export const AdjustInventoryForm = ({
|
||||
return handleSuccess()
|
||||
}
|
||||
|
||||
await mutateAsync({
|
||||
stocked_quantity: value.stocked_quantity,
|
||||
})
|
||||
try {
|
||||
await mutateAsync({
|
||||
stocked_quantity: value.stocked_quantity,
|
||||
})
|
||||
|
||||
toast.success(t("general.success"), {
|
||||
description: t("inventory.toast.updateLevel"),
|
||||
dismissLabel: t("actions.close"),
|
||||
})
|
||||
} catch (e) {
|
||||
toast.error(t("general.error"), {
|
||||
description: e.message,
|
||||
dismissLabel: t("actions.close"),
|
||||
})
|
||||
}
|
||||
|
||||
return handleSuccess()
|
||||
})
|
||||
@@ -141,7 +153,7 @@ export const AdjustInventoryForm = ({
|
||||
{t("actions.cancel")}
|
||||
</Button>
|
||||
</RouteDrawer.Close>
|
||||
<Button type="submit" size="small" isLoading={false}>
|
||||
<Button type="submit" size="small" isLoading={isLoading}>
|
||||
{t("actions.save")}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
+13
-4
@@ -1,6 +1,6 @@
|
||||
import * as zod from "zod"
|
||||
|
||||
import { Button, Input } from "@medusajs/ui"
|
||||
import { Button, Input, toast } from "@medusajs/ui"
|
||||
import {
|
||||
RouteDrawer,
|
||||
useRouteModal,
|
||||
@@ -52,13 +52,22 @@ export const EditInventoryItemAttributesForm = ({
|
||||
resolver: zodResolver(EditInventoryItemAttributesSchema),
|
||||
})
|
||||
|
||||
const { mutateAsync } = useUpdateInventoryItem(item.id)
|
||||
const { mutateAsync, isPending: isLoading } = useUpdateInventoryItem(item.id)
|
||||
|
||||
const handleSubmit = form.handleSubmit(async (values) => {
|
||||
mutateAsync(values, {
|
||||
await mutateAsync(values, {
|
||||
onSuccess: () => {
|
||||
toast.success(t("general.success"), {
|
||||
description: t("inventory.toast.update"),
|
||||
dismissLabel: t("actions.close"),
|
||||
})
|
||||
handleSuccess()
|
||||
},
|
||||
onError: (error) =>
|
||||
toast.error(t("general.error"), {
|
||||
description: error.message,
|
||||
dismissLabel: t("actions.close"),
|
||||
}),
|
||||
})
|
||||
})
|
||||
|
||||
@@ -241,7 +250,7 @@ export const EditInventoryItemAttributesForm = ({
|
||||
{t("actions.cancel")}
|
||||
</Button>
|
||||
</RouteDrawer.Close>
|
||||
<Button type="submit" size="small" isLoading={false}>
|
||||
<Button type="submit" size="small" isLoading={isLoading}>
|
||||
{t("actions.save")}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ export const InventoryItemAttributesEdit = () => {
|
||||
|
||||
const {
|
||||
inventory_item: inventoryItem,
|
||||
isLoading,
|
||||
isPending: isLoading,
|
||||
isError,
|
||||
error,
|
||||
} = useInventoryItem(id!)
|
||||
|
||||
+12
-3
@@ -1,6 +1,6 @@
|
||||
import * as zod from "zod"
|
||||
|
||||
import { Button, Input } from "@medusajs/ui"
|
||||
import { Button, Input, toast } from "@medusajs/ui"
|
||||
import {
|
||||
RouteDrawer,
|
||||
useRouteModal,
|
||||
@@ -39,13 +39,22 @@ export const EditInventoryItemForm = ({ item }: EditInventoryItemFormProps) => {
|
||||
resolver: zodResolver(EditInventoryItemSchema),
|
||||
})
|
||||
|
||||
const { mutateAsync } = useUpdateInventoryItem(item.id)
|
||||
const { mutateAsync, isPending: isLoading } = useUpdateInventoryItem(item.id)
|
||||
|
||||
const handleSubmit = form.handleSubmit(async (values) => {
|
||||
mutateAsync(values as any, {
|
||||
onSuccess: () => {
|
||||
toast.success(t("general.success"), {
|
||||
description: t("inventory.toast.update"),
|
||||
dismissLabel: t("actions.close"),
|
||||
})
|
||||
handleSuccess()
|
||||
},
|
||||
onError: (e) =>
|
||||
toast.error(t("general.error"), {
|
||||
description: e.message,
|
||||
dismissLabel: t("actions.close"),
|
||||
}),
|
||||
})
|
||||
})
|
||||
|
||||
@@ -94,7 +103,7 @@ export const EditInventoryItemForm = ({ item }: EditInventoryItemFormProps) => {
|
||||
{t("actions.cancel")}
|
||||
</Button>
|
||||
</RouteDrawer.Close>
|
||||
<Button type="submit" size="small" isLoading={false}>
|
||||
<Button type="submit" size="small" isLoading={isLoading}>
|
||||
{t("actions.save")}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ export const InventoryItemEdit = () => {
|
||||
|
||||
const {
|
||||
inventory_item: inventoryItem,
|
||||
isLoading,
|
||||
isPending: isLoading,
|
||||
isError,
|
||||
error,
|
||||
} = useInventoryItem(id!)
|
||||
|
||||
+5
-5
@@ -1,5 +1,5 @@
|
||||
import { Container, Heading, Text } from "@medusajs/ui"
|
||||
import { InventoryNext, ProductVariantDTO } from "@medusajs/types"
|
||||
import { Container, Heading } from "@medusajs/ui"
|
||||
import { ProductVariantDTO } from "@medusajs/types"
|
||||
|
||||
import { ActionMenu } from "../../../../components/common/action-menu"
|
||||
import { InventoryItemRes } from "../../../../types/api-responses"
|
||||
@@ -52,7 +52,7 @@ export const InventoryItemGeneralSection = ({
|
||||
title={t("fields.inStock")}
|
||||
value={getQuantityFormat(
|
||||
inventoryItem.stocked_quantity,
|
||||
inventoryItem.location_levels.length
|
||||
inventoryItem.location_levels?.length
|
||||
)}
|
||||
/>
|
||||
|
||||
@@ -60,14 +60,14 @@ export const InventoryItemGeneralSection = ({
|
||||
title={t("inventory.reserved")}
|
||||
value={getQuantityFormat(
|
||||
inventoryItem.reserved_quantity,
|
||||
inventoryItem.location_levels.length
|
||||
inventoryItem.location_levels?.length
|
||||
)}
|
||||
/>
|
||||
<SectionRow
|
||||
title={t("inventory.available")}
|
||||
value={getQuantityFormat(
|
||||
inventoryItem.stocked_quantity - inventoryItem.reserved_quantity,
|
||||
inventoryItem.location_levels.length
|
||||
inventoryItem.location_levels?.length
|
||||
)}
|
||||
/>
|
||||
</Container>
|
||||
|
||||
-1
@@ -3,7 +3,6 @@ import { Button, Container, Heading } from "@medusajs/ui"
|
||||
import { InventoryItemRes } from "../../../../types/api-responses"
|
||||
import { ItemLocationListTable } from "./location-levels-table/location-list-table"
|
||||
import { Link } from "react-router-dom"
|
||||
import { ReservationItemTable } from "./reservations-table/reservation-list-table"
|
||||
import { useTranslation } from "react-i18next"
|
||||
|
||||
type InventoryItemLocationLevelsSectionProps = {
|
||||
|
||||
+10
-5
@@ -15,11 +15,16 @@ export const ItemLocationListTable = ({
|
||||
pageSize: PAGE_SIZE,
|
||||
})
|
||||
|
||||
const { inventory_levels, count, isLoading, isError, error } =
|
||||
useInventoryItemLevels(inventory_item_id, {
|
||||
...searchParams,
|
||||
fields: "*stock_locations",
|
||||
})
|
||||
const {
|
||||
inventory_levels,
|
||||
count,
|
||||
isPending: isLoading,
|
||||
isError,
|
||||
error,
|
||||
} = useInventoryItemLevels(inventory_item_id, {
|
||||
...searchParams,
|
||||
fields: "*stock_locations",
|
||||
})
|
||||
|
||||
const columns = useLocationListTableColumns()
|
||||
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ export const LocationItem = ({
|
||||
}: LocationItemProps) => {
|
||||
return (
|
||||
<div
|
||||
className={clx("flex w-full rounded-lg border px-2 py-2 gap-x-2", {
|
||||
className={clx("flex w-full gap-x-2 rounded-lg border px-2 py-2", {
|
||||
"border-ui-border-interactive ": selected,
|
||||
})}
|
||||
onClick={() => onSelect(!selected)}
|
||||
|
||||
+25
-16
@@ -1,14 +1,11 @@
|
||||
import * as zod from "zod"
|
||||
|
||||
import { Button, Table, Text } from "@medusajs/ui"
|
||||
import { Button, Text, toast } from "@medusajs/ui"
|
||||
import {
|
||||
RouteDrawer,
|
||||
useRouteModal,
|
||||
} from "../../../../../../components/route-modal"
|
||||
import {
|
||||
useBatchInventoryItemLevels,
|
||||
useUpdateInventoryItem,
|
||||
} from "../../../../../../hooks/api/inventory"
|
||||
import { useBatchInventoryItemLevels } from "../../../../../../hooks/api/inventory"
|
||||
import { useFieldArray, useForm } from "react-hook-form"
|
||||
|
||||
import { InventoryItemRes } from "../../../../../../types/api-responses"
|
||||
@@ -35,13 +32,13 @@ const EditInventoryItemAttributesSchema = z.object({
|
||||
|
||||
const getDefaultValues = (
|
||||
allLocations: StockLocationDTO[],
|
||||
existinLevels: Set<string>
|
||||
existingLevels: Set<string>
|
||||
) => {
|
||||
return {
|
||||
locations: allLocations.map((location) => ({
|
||||
...location,
|
||||
location_id: location.id,
|
||||
selected: existinLevels.has(location.id),
|
||||
selected: existingLevels.has(location.id),
|
||||
})),
|
||||
}
|
||||
}
|
||||
@@ -97,14 +94,26 @@ export const ManageLocationsForm = ({
|
||||
return handleSuccess()
|
||||
}
|
||||
|
||||
await mutateAsync({
|
||||
creates: selectedLocations.map((location_id) => ({
|
||||
location_id,
|
||||
})),
|
||||
deletes: unselectedLocations,
|
||||
})
|
||||
try {
|
||||
await mutateAsync({
|
||||
creates: selectedLocations.map((location_id) => ({
|
||||
location_id,
|
||||
})),
|
||||
deletes: unselectedLocations,
|
||||
})
|
||||
|
||||
return handleSuccess()
|
||||
handleSuccess()
|
||||
|
||||
toast.success(t("general.success"), {
|
||||
description: t("inventory.toast.update"),
|
||||
dismissLabel: t("actions.close"),
|
||||
})
|
||||
} catch (e) {
|
||||
toast.error(t("general.error"), {
|
||||
description: e.message,
|
||||
dismissLabel: t("actions.close"),
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
@@ -114,7 +123,7 @@ export const ManageLocationsForm = ({
|
||||
className="flex flex-1 flex-col overflow-hidden"
|
||||
>
|
||||
<RouteDrawer.Body className="flex flex-1 flex-col gap-y-4 overflow-auto">
|
||||
<div className="grid grid-rows-2 divide-y rounded-lg border text-ui-fg-subtle shadow-elevation-card-rest">
|
||||
<div className="text-ui-fg-subtle shadow-elevation-card-rest grid grid-rows-2 divide-y rounded-lg border">
|
||||
<div className="grid grid-cols-2 divide-x">
|
||||
<Text className="px-2 py-1.5" size="small" leading="compact">
|
||||
{t("fields.title")}
|
||||
@@ -136,7 +145,7 @@ export const ManageLocationsForm = ({
|
||||
<Text size="small" weight="plus" leading="compact">
|
||||
{t("locations.domain")}
|
||||
</Text>
|
||||
<div className="flex w-full justify-between text-ui-fg-subtle">
|
||||
<div className="text-ui-fg-subtle flex w-full justify-between">
|
||||
<Text size="small" leading="compact">
|
||||
{t("locations.selectLocations")}
|
||||
</Text>
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ export const ManageLocationsDrawer = () => {
|
||||
|
||||
const {
|
||||
inventory_item: inventoryItem,
|
||||
isLoading,
|
||||
isPending: isLoading,
|
||||
isError,
|
||||
error,
|
||||
} = useInventoryItem(id!)
|
||||
|
||||
+10
-5
@@ -16,11 +16,16 @@ export const ReservationItemTable = ({
|
||||
pageSize: PAGE_SIZE,
|
||||
})
|
||||
|
||||
const { reservations, count, isLoading, isError, error } =
|
||||
useReservationItems({
|
||||
...searchParams,
|
||||
inventory_item_id: [inventoryItem.id],
|
||||
})
|
||||
const {
|
||||
reservations,
|
||||
count,
|
||||
isPending: isLoading,
|
||||
isError,
|
||||
error,
|
||||
} = useReservationItems({
|
||||
...searchParams,
|
||||
inventory_item_id: [inventoryItem.id],
|
||||
})
|
||||
|
||||
const columns = useInventoryTableColumns({ sku: inventoryItem.sku! })
|
||||
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
export { InventoryDeatil as Component } from "./inventory-detail"
|
||||
export { InventoryDetail as Component } from "./inventory-detail"
|
||||
export { inventoryItemLoader as loader } from "./loader"
|
||||
|
||||
+13
-6
@@ -5,19 +5,26 @@ import { InventoryItemGeneralSection } from "./components/inventory-item-general
|
||||
import { InventoryItemLocationLevelsSection } from "./components/inventory-item-location-levels"
|
||||
import { InventoryItemReservationsSection } from "./components/inventory-item-reservations"
|
||||
import { JsonViewSection } from "../../../components/common/json-view-section"
|
||||
import { inventoryItemLoader } from "./loader"
|
||||
import { useInventoryItem } from "../../../hooks/api/inventory"
|
||||
import { inventoryItemLoader } from "./loader"
|
||||
|
||||
export const InventoryDeatil = () => {
|
||||
export const InventoryDetail = () => {
|
||||
const { id } = useParams()
|
||||
|
||||
const initialData = useLoaderData() as Awaited<
|
||||
ReturnType<typeof inventoryItemLoader>
|
||||
>
|
||||
|
||||
const { inventory_item, isLoading, isError, error } = useInventoryItem(
|
||||
const {
|
||||
inventory_item,
|
||||
isPending: isLoading,
|
||||
isError,
|
||||
error,
|
||||
} = useInventoryItem(
|
||||
id!,
|
||||
{},
|
||||
{
|
||||
fields: "*variants",
|
||||
},
|
||||
{
|
||||
initialData,
|
||||
}
|
||||
@@ -38,7 +45,7 @@ export const InventoryDeatil = () => {
|
||||
return (
|
||||
<div className="flex flex-col gap-y-2">
|
||||
<div className="flex flex-col gap-x-4 lg:flex-row lg:items-start">
|
||||
<div className="w-full flex flex-col gap-y-2">
|
||||
<div className="flex w-full flex-col gap-y-2">
|
||||
<InventoryItemGeneralSection inventoryItem={inventory_item} />
|
||||
<InventoryItemLocationLevelsSection inventoryItem={inventory_item} />
|
||||
<InventoryItemReservationsSection inventoryItem={inventory_item} />
|
||||
@@ -47,7 +54,7 @@ export const InventoryDeatil = () => {
|
||||
</div>
|
||||
<Outlet />
|
||||
</div>
|
||||
<div className="w-full lg:max-w-[400px] max-w-[100%] mt-2 lg:mt-0 flex flex-col gap-y-2">
|
||||
<div className="mt-2 flex w-full max-w-[100%] flex-col gap-y-2 lg:mt-0 lg:max-w-[400px]">
|
||||
<InventoryItemAttributeSection inventoryItem={inventory_item} />
|
||||
<div className="lg:hidden">
|
||||
<JsonViewSection data={inventory_item} />
|
||||
|
||||
+11
-5
@@ -1,7 +1,7 @@
|
||||
import { Container, Heading } from "@medusajs/ui"
|
||||
import { InventoryNext } from "@medusajs/types"
|
||||
|
||||
import { DataTable } from "../../../../components/table/data-table"
|
||||
import { InventoryNext } from "@medusajs/types"
|
||||
import { useDataTable } from "../../../../hooks/use-data-table"
|
||||
import { useInventoryItems } from "../../../../hooks/api/inventory"
|
||||
import { useInventoryTableColumns } from "./use-inventory-table-columns"
|
||||
@@ -17,10 +17,16 @@ export const InventoryListTable = () => {
|
||||
const { searchParams, raw } = useInventoryTableQuery({
|
||||
pageSize: PAGE_SIZE,
|
||||
})
|
||||
const { inventory_items, count, isLoading, isError, error } =
|
||||
useInventoryItems({
|
||||
...searchParams,
|
||||
})
|
||||
|
||||
const {
|
||||
inventory_items,
|
||||
count,
|
||||
isPending: isLoading,
|
||||
isError,
|
||||
error,
|
||||
} = useInventoryItems({
|
||||
...searchParams,
|
||||
})
|
||||
|
||||
const filters = useInventoryTableFilters()
|
||||
const columns = useInventoryTableColumns()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { zodResolver } from "@hookform/resolvers/zod"
|
||||
import { UserRoles } from "@medusajs/medusa"
|
||||
import { Alert, Button, Heading, Input, Text } from "@medusajs/ui"
|
||||
import { Alert, Button, Heading, Input, Text, toast } from "@medusajs/ui"
|
||||
import { AnimatePresence, motion } from "framer-motion"
|
||||
import { Trans, useTranslation } from "react-i18next"
|
||||
import { Link, useSearchParams } from "react-router-dom"
|
||||
@@ -49,7 +49,7 @@ export const Invite = () => {
|
||||
const isValidInvite = invite && validateDecodedInvite(invite)
|
||||
|
||||
return (
|
||||
<div className="min-h-dvh w-dvw bg-ui-bg-base relative flex items-center justify-center p-4">
|
||||
<div className="bg-ui-bg-base relative flex min-h-dvh w-dvw items-center justify-center p-4">
|
||||
<div className="flex w-full max-w-[300px] flex-col items-center">
|
||||
<LogoBox
|
||||
className="mb-4"
|
||||
@@ -204,10 +204,10 @@ const CreateView = ({
|
||||
},
|
||||
})
|
||||
|
||||
const { mutateAsync: createAuthUser, isLoading: isCreatingAuthUser } =
|
||||
const { mutateAsync: createAuthUser, isPending: isCreatingAuthUser } =
|
||||
useV2CreateAuthUser()
|
||||
|
||||
const { mutateAsync: acceptInvite, isLoading: isAcceptingInvite } =
|
||||
const { mutateAsync: acceptInvite, isPending: isAcceptingInvite } =
|
||||
useV2AcceptInvite(token)
|
||||
|
||||
const handleSubmit = form.handleSubmit(async (data) => {
|
||||
@@ -228,6 +228,10 @@ const CreateView = ({
|
||||
token: authToken,
|
||||
})
|
||||
onSuccess()
|
||||
toast.success(t("general.success"), {
|
||||
description: t("invite.toast.accepted"),
|
||||
dismissLabel: t("actions.close"),
|
||||
})
|
||||
} catch (error) {
|
||||
if (isAxiosError(error) && error.response?.status === 400) {
|
||||
form.setError("root", {
|
||||
|
||||
+17
-10
@@ -1,5 +1,5 @@
|
||||
import { zodResolver } from "@hookform/resolvers/zod"
|
||||
import { Button, Heading, Input, Text } from "@medusajs/ui"
|
||||
import { Button, Heading, Input, Text, toast } from "@medusajs/ui"
|
||||
import { useForm } from "react-hook-form"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import * as zod from "zod"
|
||||
@@ -49,17 +49,24 @@ export const CreateLocationForm = () => {
|
||||
const { mutateAsync, isPending } = useCreateStockLocation()
|
||||
|
||||
const handleSubmit = form.handleSubmit(async (values) => {
|
||||
mutateAsync(
|
||||
{
|
||||
try {
|
||||
await mutateAsync({
|
||||
name: values.name,
|
||||
address: values.address,
|
||||
},
|
||||
{
|
||||
onSuccess: () => {
|
||||
handleSuccess("/settings/locations")
|
||||
},
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
handleSuccess("/settings/locations")
|
||||
|
||||
toast.success(t("general.success"), {
|
||||
description: t("locations.toast.create"),
|
||||
dismissLabel: t("actions.close"),
|
||||
})
|
||||
} catch (e) {
|
||||
toast.error(t("general.error"), {
|
||||
description: e.message,
|
||||
dismissLabel: t("actions.close"),
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
|
||||
+17
-5
@@ -1,6 +1,6 @@
|
||||
import { PencilSquare, Trash } from "@medusajs/icons"
|
||||
import { SalesChannelDTO } from "@medusajs/types"
|
||||
import { Button, Container, Heading, usePrompt } from "@medusajs/ui"
|
||||
import { Button, Container, Heading, toast, usePrompt } from "@medusajs/ui"
|
||||
import { createColumnHelper } from "@tanstack/react-table"
|
||||
import { useAdminRemoveLocationFromSalesChannel } from "medusa-react"
|
||||
import { useMemo } from "react"
|
||||
@@ -82,10 +82,22 @@ const SalesChannelActions = ({
|
||||
return
|
||||
}
|
||||
|
||||
await mutateAsync({
|
||||
location_id: locationId,
|
||||
sales_channel_id: salesChannel.id,
|
||||
})
|
||||
try {
|
||||
await mutateAsync({
|
||||
location_id: locationId,
|
||||
sales_channel_id: salesChannel.id,
|
||||
})
|
||||
|
||||
toast.success(t("general.success"), {
|
||||
description: t("locations.toast.removeChannel"),
|
||||
dismissLabel: t("actions.close"),
|
||||
})
|
||||
} catch (e) {
|
||||
toast.error(t("general.error"), {
|
||||
description: e.message,
|
||||
dismissLabel: t("actions.close"),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
+6
-1
@@ -7,7 +7,12 @@ import { LocationSalesChannelSection } from "./components/location-sales-channel
|
||||
|
||||
export const LocationDetail = () => {
|
||||
const { id } = useParams()
|
||||
const { stock_location, isLoading, isError, error } = useStockLocation(id!, {
|
||||
const {
|
||||
stock_location,
|
||||
isPending: isLoading,
|
||||
isError,
|
||||
error,
|
||||
} = useStockLocation(id!, {
|
||||
fields: "*address,*sales_channels",
|
||||
})
|
||||
|
||||
|
||||
+16
-10
@@ -1,5 +1,5 @@
|
||||
import { zodResolver } from "@hookform/resolvers/zod"
|
||||
import { Button, Input } from "@medusajs/ui"
|
||||
import { Button, Input, toast } from "@medusajs/ui"
|
||||
import { useForm } from "react-hook-form"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import * as zod from "zod"
|
||||
@@ -55,17 +55,23 @@ export const EditLocationForm = ({ location }: EditLocationFormProps) => {
|
||||
const { mutateAsync, isPending } = useUpdateStockLocation(location.id)
|
||||
|
||||
const handleSubmit = form.handleSubmit(async (values) => {
|
||||
mutateAsync(
|
||||
{
|
||||
try {
|
||||
await mutateAsync({
|
||||
name: values.name,
|
||||
address: values.address,
|
||||
},
|
||||
{
|
||||
onSuccess: () => {
|
||||
handleSuccess()
|
||||
},
|
||||
}
|
||||
)
|
||||
})
|
||||
handleSuccess()
|
||||
|
||||
toast.success(t("general.success"), {
|
||||
description: t("locations.toast.update"),
|
||||
dismissLabel: t("actions.close"),
|
||||
})
|
||||
} catch (e) {
|
||||
toast.error(t("general.error"), {
|
||||
description: e.message,
|
||||
dismissLabel: t("actions.close"),
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
|
||||
+7
-5
@@ -2,14 +2,18 @@ import { Heading } from "@medusajs/ui"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import { useParams } from "react-router-dom"
|
||||
import { RouteDrawer } from "../../../components/route-modal"
|
||||
import { useStockLocations } from "../../../hooks/api/stock-locations"
|
||||
import { useStockLocation } from "../../../hooks/api/stock-locations"
|
||||
import { EditLocationForm } from "./components/edit-location-form"
|
||||
|
||||
export const LocationEdit = () => {
|
||||
const { id } = useParams()
|
||||
|
||||
const { stock_locations, isLoading, isError, error } = useStockLocations({
|
||||
id,
|
||||
const {
|
||||
stock_location,
|
||||
isPending: isLoading,
|
||||
isError,
|
||||
error,
|
||||
} = useStockLocation(id, {
|
||||
fields: "*address",
|
||||
})
|
||||
|
||||
@@ -19,8 +23,6 @@ export const LocationEdit = () => {
|
||||
throw error
|
||||
}
|
||||
|
||||
const stock_location = stock_locations?.[0]
|
||||
|
||||
return (
|
||||
<RouteDrawer>
|
||||
<RouteDrawer.Header>
|
||||
|
||||
+13
-7
@@ -19,16 +19,21 @@ export const LocationsListTable = () => {
|
||||
* Note: The endpoint is bugged and does not return count, causing the table to not render
|
||||
* any rows.
|
||||
*/
|
||||
const { stock_locations, count, isLoading, isError, error } =
|
||||
useStockLocations({
|
||||
...searchParams,
|
||||
fields: "*address",
|
||||
})
|
||||
const {
|
||||
stock_locations = [],
|
||||
count,
|
||||
isLoading,
|
||||
isError,
|
||||
error,
|
||||
} = useStockLocations({
|
||||
...searchParams,
|
||||
fields: "*address",
|
||||
})
|
||||
|
||||
const columns = useLocationTableColumns()
|
||||
|
||||
const { table } = useDataTable({
|
||||
data: stock_locations ?? [],
|
||||
data: stock_locations,
|
||||
columns,
|
||||
count,
|
||||
enablePagination: true,
|
||||
@@ -56,7 +61,8 @@ export const LocationsListTable = () => {
|
||||
count={count || 1}
|
||||
columns={columns}
|
||||
navigateTo={(row) => row.id}
|
||||
isLoading={isLoading}
|
||||
// TODO: revisit loader - on query change this will cause unmounting of the table, rendering loader briefly and again rendering table which will make search input unfocused
|
||||
// isLoading={isLoading}
|
||||
queryObject={raw}
|
||||
pagination
|
||||
search
|
||||
|
||||
+2
-1
@@ -7,11 +7,12 @@ export const useLocationTableQuery = ({
|
||||
pageSize?: number
|
||||
prefix?: string
|
||||
}) => {
|
||||
const raw = useQueryParams(["offset"], prefix)
|
||||
const raw = useQueryParams(["q", "offset"], prefix)
|
||||
|
||||
const searchParams = {
|
||||
limit: pageSize,
|
||||
offset: raw.offset,
|
||||
q: raw.q,
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { zodResolver } from "@hookform/resolvers/zod"
|
||||
import { Button, Heading, Input, Text } from "@medusajs/ui"
|
||||
import { Alert, Button, Heading, Input, Text } from "@medusajs/ui"
|
||||
import { useForm } from "react-hook-form"
|
||||
import { Trans, useTranslation } from "react-i18next"
|
||||
import { Link, useLocation, useNavigate } from "react-router-dom"
|
||||
@@ -34,40 +34,38 @@ export const Login = () => {
|
||||
const { mutateAsync, isPending } = useEmailPassLogin()
|
||||
|
||||
const handleSubmit = form.handleSubmit(async ({ email, password }) => {
|
||||
await mutateAsync(
|
||||
{
|
||||
try {
|
||||
await mutateAsync({
|
||||
email,
|
||||
password,
|
||||
},
|
||||
{
|
||||
onSuccess: () => {
|
||||
navigate(from, { replace: true })
|
||||
},
|
||||
onError: (error) => {
|
||||
if (isAxiosError(error)) {
|
||||
if (error.response?.status === 401) {
|
||||
form.setError("email", {
|
||||
type: "manual",
|
||||
})
|
||||
})
|
||||
|
||||
form.setError("password", {
|
||||
type: "manual",
|
||||
message: t("errors.invalidCredentials"),
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
form.setError("root.serverError", {
|
||||
navigate(from, { replace: true })
|
||||
} catch (error) {
|
||||
if (isAxiosError(error)) {
|
||||
if (error.response?.status === 401) {
|
||||
form.setError("email", {
|
||||
type: "manual",
|
||||
message: t("errors.serverError"),
|
||||
})
|
||||
},
|
||||
|
||||
form.setError("password", {
|
||||
type: "manual",
|
||||
message: t("errors.invalidCredentials"),
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
form.setError("root.serverError", {
|
||||
type: "manual",
|
||||
message: t("errors.serverError"),
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const serverError = form.formState.errors?.root?.serverError?.message
|
||||
|
||||
return (
|
||||
<div className="bg-ui-bg-base flex min-h-dvh w-dvw items-center justify-center">
|
||||
<div className="m-4 flex w-full max-w-[300px] flex-col items-center">
|
||||
@@ -123,6 +121,11 @@ export const Login = () => {
|
||||
{t("actions.continue")}
|
||||
</Button>
|
||||
</form>
|
||||
{serverError && (
|
||||
<Alert className="mt-4" dismissible variant="error">
|
||||
{serverError}
|
||||
</Alert>
|
||||
)}
|
||||
</Form>
|
||||
<div className="my-6 h-px w-full border-b border-dotted" />
|
||||
<span className="text-ui-fg-subtle txt-small">
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@ import { useMe } from "../../../hooks/api/users"
|
||||
import { ProfileGeneralSection } from "./components/profile-general-section"
|
||||
|
||||
export const ProfileDetail = () => {
|
||||
const { user, isLoading, isError, error } = useMe()
|
||||
const { user, isPending: isLoading, isError, error } = useMe()
|
||||
|
||||
if (isLoading) {
|
||||
return <div>Loading...</div>
|
||||
@@ -14,7 +14,7 @@ export const ProfileDetail = () => {
|
||||
throw error
|
||||
}
|
||||
|
||||
throw json("An unknown error has occured", 500)
|
||||
throw json("An unknown error has occurred", 500)
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
+19
-14
@@ -1,5 +1,5 @@
|
||||
import { zodResolver } from "@hookform/resolvers/zod"
|
||||
import { Button, Input, Select, Switch } from "@medusajs/ui"
|
||||
import { Button, Input, Select, Switch, toast } from "@medusajs/ui"
|
||||
import { useForm } from "react-hook-form"
|
||||
import { Trans, useTranslation } from "react-i18next"
|
||||
import * as zod from "zod"
|
||||
@@ -39,8 +39,8 @@ export const EditProfileForm = ({ user, usageInsights }: EditProfileProps) => {
|
||||
resolver: zodResolver(EditProfileSchema),
|
||||
})
|
||||
|
||||
const changeLanguage = (code: string) => {
|
||||
i18n.changeLanguage(code)
|
||||
const changeLanguage = async (code: string) => {
|
||||
await i18n.changeLanguage(code)
|
||||
}
|
||||
|
||||
const sortedLanguages = languages.sort((a, b) =>
|
||||
@@ -50,21 +50,26 @@ export const EditProfileForm = ({ user, usageInsights }: EditProfileProps) => {
|
||||
const { mutateAsync, isPending } = useUpdateUser(user.id!)
|
||||
|
||||
const handleSubmit = form.handleSubmit(async (values) => {
|
||||
await mutateAsync(
|
||||
{
|
||||
try {
|
||||
await mutateAsync({
|
||||
first_name: values.first_name,
|
||||
last_name: values.last_name,
|
||||
},
|
||||
{
|
||||
onError: () => {
|
||||
return
|
||||
},
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
changeLanguage(values.language)
|
||||
await changeLanguage(values.language)
|
||||
|
||||
handleSuccess()
|
||||
handleSuccess()
|
||||
|
||||
toast.success(t("general.success"), {
|
||||
description: t("profile.toast.edit"),
|
||||
dismissLabel: t("actions.close"),
|
||||
})
|
||||
} catch (e) {
|
||||
toast.error(t("general.error"), {
|
||||
description: e.message,
|
||||
dismissLabel: t("actions.close"),
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useMe } from "../../../hooks/api/users"
|
||||
import { EditProfileForm } from "./components/edit-profile-form/edit-profile-form"
|
||||
|
||||
export const ProfileEdit = () => {
|
||||
const { user, isLoading, isError, error } = useMe()
|
||||
const { user, isPending: isLoading, isError, error } = useMe()
|
||||
|
||||
const { t } = useTranslation()
|
||||
|
||||
|
||||
+17
-2
@@ -1,6 +1,6 @@
|
||||
import { zodResolver } from "@hookform/resolvers/zod"
|
||||
import { SalesChannelDTO } from "@medusajs/types"
|
||||
import { Button, Checkbox, Hint, Tooltip } from "@medusajs/ui"
|
||||
import { Button, Checkbox, Hint, toast, Tooltip } from "@medusajs/ui"
|
||||
import { keepPreviousData } from "@tanstack/react-query"
|
||||
import {
|
||||
OnChangeFn,
|
||||
@@ -67,7 +67,13 @@ export const AddProductsToSalesChannelForm = ({
|
||||
}
|
||||
|
||||
const { searchParams, raw } = useProductTableQuery({ pageSize: PAGE_SIZE })
|
||||
const { products, count, isLoading, isError, error } = useProducts(
|
||||
const {
|
||||
products,
|
||||
count,
|
||||
isPending: isLoading,
|
||||
isError,
|
||||
error,
|
||||
} = useProducts(
|
||||
{
|
||||
expand: "variants,sales_channels",
|
||||
...searchParams,
|
||||
@@ -108,8 +114,17 @@ export const AddProductsToSalesChannelForm = ({
|
||||
},
|
||||
{
|
||||
onSuccess: () => {
|
||||
toast.success(t("general.success"), {
|
||||
description: t("salesChannels.toast.update"),
|
||||
dismissLabel: t("actions.close"),
|
||||
})
|
||||
handleSuccess()
|
||||
},
|
||||
onError: (error) =>
|
||||
toast.error(t("general.error"), {
|
||||
description: error.message,
|
||||
dismissLabel: t("actions.close"),
|
||||
}),
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
+6
-1
@@ -5,7 +5,12 @@ import { AddProductsToSalesChannelForm } from "./components"
|
||||
|
||||
export const SalesChannelAddProducts = () => {
|
||||
const { id } = useParams()
|
||||
const { sales_channel, isLoading, isError, error } = useSalesChannel(id!)
|
||||
const {
|
||||
sales_channel,
|
||||
isPending: isLoading,
|
||||
isError,
|
||||
error,
|
||||
} = useSalesChannel(id!)
|
||||
|
||||
if (isError) {
|
||||
throw error
|
||||
|
||||
+18
-1
@@ -1,5 +1,13 @@
|
||||
import { zodResolver } from "@hookform/resolvers/zod"
|
||||
import { Button, Heading, Input, Switch, Text, Textarea } from "@medusajs/ui"
|
||||
import {
|
||||
Button,
|
||||
Heading,
|
||||
Input,
|
||||
Switch,
|
||||
Text,
|
||||
Textarea,
|
||||
toast,
|
||||
} from "@medusajs/ui"
|
||||
import { useForm } from "react-hook-form"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import * as zod from "zod"
|
||||
@@ -40,8 +48,17 @@ export const CreateSalesChannelForm = () => {
|
||||
},
|
||||
{
|
||||
onSuccess: ({ sales_channel }) => {
|
||||
toast.success(t("general.success"), {
|
||||
description: t("salesChannels.toast.create"),
|
||||
dismissLabel: t("actions.close"),
|
||||
})
|
||||
handleSuccess(`../${sales_channel.id}`)
|
||||
},
|
||||
onError: (error) =>
|
||||
toast.success(t("general.success"), {
|
||||
description: error.message,
|
||||
dismissLabel: t("actions.close"),
|
||||
}),
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
+23
-6
@@ -1,5 +1,12 @@
|
||||
import { PencilSquare, Trash } from "@medusajs/icons"
|
||||
import { Container, Heading, StatusBadge, Text, usePrompt } from "@medusajs/ui"
|
||||
import {
|
||||
Container,
|
||||
Heading,
|
||||
StatusBadge,
|
||||
Text,
|
||||
toast,
|
||||
usePrompt,
|
||||
} from "@medusajs/ui"
|
||||
import { useTranslation } from "react-i18next"
|
||||
|
||||
import { SalesChannelDTO } from "@medusajs/types"
|
||||
@@ -36,11 +43,21 @@ export const SalesChannelGeneralSection = ({
|
||||
return
|
||||
}
|
||||
|
||||
await mutateAsync(undefined, {
|
||||
onSuccess: () => {
|
||||
navigate("/settings/sales-channels", { replace: true })
|
||||
},
|
||||
})
|
||||
try {
|
||||
await mutateAsync()
|
||||
|
||||
navigate("/settings/sales-channels", { replace: true })
|
||||
|
||||
toast.success(t("general.success"), {
|
||||
description: t("salesChannels.toast.delete"),
|
||||
dismissLabel: t("actions.close"),
|
||||
})
|
||||
} catch (e) {
|
||||
toast.error(t("general.error"), {
|
||||
description: e.message,
|
||||
dismissLabel: t("actions.close"),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
+39
-5
@@ -1,5 +1,12 @@
|
||||
import { PencilSquare, Trash } from "@medusajs/icons"
|
||||
import { Button, Checkbox, Container, Heading, usePrompt } from "@medusajs/ui"
|
||||
import {
|
||||
Button,
|
||||
Checkbox,
|
||||
Container,
|
||||
Heading,
|
||||
toast,
|
||||
usePrompt,
|
||||
} from "@medusajs/ui"
|
||||
import { RowSelectionState, createColumnHelper } from "@tanstack/react-table"
|
||||
import { useMemo, useState } from "react"
|
||||
import { useTranslation } from "react-i18next"
|
||||
@@ -29,7 +36,13 @@ export const SalesChannelProductSection = ({
|
||||
const [rowSelection, setRowSelection] = useState<RowSelectionState>({})
|
||||
|
||||
const { searchParams, raw } = useProductTableQuery({ pageSize: PAGE_SIZE })
|
||||
const { products, count, isLoading, isError, error } = useProducts(
|
||||
const {
|
||||
products,
|
||||
count,
|
||||
isPending: isLoading,
|
||||
isError,
|
||||
error,
|
||||
} = useProducts(
|
||||
{
|
||||
...searchParams,
|
||||
sales_channel_id: [salesChannel.id],
|
||||
@@ -87,8 +100,18 @@ export const SalesChannelProductSection = ({
|
||||
},
|
||||
{
|
||||
onSuccess: () => {
|
||||
toast.success(t("general.success"), {
|
||||
description: t("salesChannels.toast.update"),
|
||||
dismissLabel: t("actions.close"),
|
||||
})
|
||||
setRowSelection({})
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error(t("general.error"), {
|
||||
description: error.message,
|
||||
dismissLabel: t("actions.close"),
|
||||
})
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -199,9 +222,20 @@ const ProductListCellActions = ({
|
||||
const { mutateAsync } = useSalesChannelRemoveProducts(salesChannelId)
|
||||
|
||||
const onRemove = async () => {
|
||||
await mutateAsync({
|
||||
product_ids: [productId],
|
||||
})
|
||||
try {
|
||||
await mutateAsync({
|
||||
product_ids: [productId],
|
||||
})
|
||||
toast.success(t("general.success"), {
|
||||
description: t("salesChannels.toast.update"),
|
||||
dismissLabel: t("actions.close"),
|
||||
})
|
||||
} catch (e) {
|
||||
toast.error(t("general.error"), {
|
||||
description: e.message,
|
||||
dismissLabel: t("actions.close"),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ export const SalesChannelDetail = () => {
|
||||
>
|
||||
|
||||
const { id } = useParams()
|
||||
const { sales_channel, isLoading } = useSalesChannel(id!, {
|
||||
const { sales_channel, isPending: isLoading } = useSalesChannel(id!, {
|
||||
initialData,
|
||||
})
|
||||
|
||||
|
||||
+11
-1
@@ -1,5 +1,5 @@
|
||||
import { zodResolver } from "@hookform/resolvers/zod"
|
||||
import { Button, Input, Switch, Textarea } from "@medusajs/ui"
|
||||
import { Button, Input, Switch, Textarea, toast } from "@medusajs/ui"
|
||||
import { useForm } from "react-hook-form"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import * as zod from "zod"
|
||||
@@ -48,8 +48,18 @@ export const EditSalesChannelForm = ({
|
||||
},
|
||||
{
|
||||
onSuccess: () => {
|
||||
toast.success(t("general.success"), {
|
||||
description: t("salesChannels.toast.update"),
|
||||
dismissLabel: t("actions.close"),
|
||||
})
|
||||
handleSuccess()
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error(t("general.error"), {
|
||||
description: error.message,
|
||||
dismissLabel: t("actions.close"),
|
||||
})
|
||||
},
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
+6
-1
@@ -10,7 +10,12 @@ export const SalesChannelEdit = () => {
|
||||
const { id } = useParams()
|
||||
const { t } = useTranslation()
|
||||
|
||||
const { sales_channel, isLoading, isError, error } = useSalesChannel(id!)
|
||||
const {
|
||||
sales_channel,
|
||||
isPending: isLoading,
|
||||
isError,
|
||||
error,
|
||||
} = useSalesChannel(id!)
|
||||
|
||||
if (isError) {
|
||||
throw error
|
||||
|
||||
+22
-8
@@ -1,6 +1,6 @@
|
||||
import { PencilSquare, Trash } from "@medusajs/icons"
|
||||
import { SalesChannelDTO } from "@medusajs/types"
|
||||
import { Button, Container, Heading, usePrompt } from "@medusajs/ui"
|
||||
import { Button, Container, Heading, toast, usePrompt } from "@medusajs/ui"
|
||||
import { keepPreviousData } from "@tanstack/react-query"
|
||||
import { createColumnHelper } from "@tanstack/react-table"
|
||||
import { useMemo } from "react"
|
||||
@@ -24,12 +24,15 @@ export const SalesChannelListTable = () => {
|
||||
const { raw, searchParams } = useSalesChannelTableQuery({
|
||||
pageSize: PAGE_SIZE,
|
||||
})
|
||||
const { sales_channels, count, isLoading, isError, error } = useSalesChannels(
|
||||
searchParams,
|
||||
{
|
||||
placeholderData: keepPreviousData,
|
||||
}
|
||||
)
|
||||
const {
|
||||
sales_channels,
|
||||
count,
|
||||
isPending: isLoading,
|
||||
isError,
|
||||
error,
|
||||
} = useSalesChannels(searchParams, {
|
||||
placeholderData: keepPreviousData,
|
||||
})
|
||||
|
||||
const columns = useColumns()
|
||||
|
||||
@@ -97,7 +100,18 @@ const SalesChannelActions = ({
|
||||
return
|
||||
}
|
||||
|
||||
await mutateAsync()
|
||||
try {
|
||||
await mutateAsync()
|
||||
toast.success(t("general.success"), {
|
||||
description: t("salesChannels.toast.delete"),
|
||||
dismissLabel: t("actions.close"),
|
||||
})
|
||||
} catch (e) {
|
||||
toast.error(t("general.error"), {
|
||||
description: e.message,
|
||||
dismissLabel: t("actions.close"),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
+24
-16
@@ -1,5 +1,5 @@
|
||||
import { Currency } from "@medusajs/medusa"
|
||||
import { Button, Checkbox, Hint, Tooltip } from "@medusajs/ui"
|
||||
import { Button, Checkbox, Hint, toast, Tooltip } from "@medusajs/ui"
|
||||
import {
|
||||
OnChangeFn,
|
||||
RowSelectionState,
|
||||
@@ -68,12 +68,15 @@ export const AddCurrenciesForm = ({ store }: AddCurrenciesFormProps) => {
|
||||
prefix: PREFIX,
|
||||
})
|
||||
|
||||
const { currencies, count, isLoading, isError, error } = useCurrencies(
|
||||
searchParams,
|
||||
{
|
||||
placeholderData: keepPreviousData,
|
||||
}
|
||||
)
|
||||
const {
|
||||
currencies,
|
||||
count,
|
||||
isPending: isLoading,
|
||||
isError,
|
||||
error,
|
||||
} = useCurrencies(searchParams, {
|
||||
placeholderData: keepPreviousData,
|
||||
})
|
||||
|
||||
const preSelectedRows = store.supported_currency_codes.map((c) => c)
|
||||
|
||||
@@ -101,16 +104,21 @@ export const AddCurrenciesForm = ({ store }: AddCurrenciesFormProps) => {
|
||||
new Set([...data.currencies, ...preSelectedRows])
|
||||
) as string[]
|
||||
|
||||
await mutateAsync(
|
||||
{
|
||||
try {
|
||||
await mutateAsync({
|
||||
supported_currency_codes: currencies,
|
||||
},
|
||||
{
|
||||
onSuccess: () => {
|
||||
handleSuccess()
|
||||
},
|
||||
}
|
||||
)
|
||||
})
|
||||
toast.success(t("general.success"), {
|
||||
description: t("store.toast.currenciesUpdated"),
|
||||
dismissLabel: t("actions.close"),
|
||||
})
|
||||
handleSuccess()
|
||||
} catch (e) {
|
||||
toast.error(t("general.error"), {
|
||||
description: e.message,
|
||||
dismissLabel: t("actions.close"),
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
if (isError) {
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ import { useStore } from "../../../hooks/api/store"
|
||||
import { AddCurrenciesForm } from "./components/add-currencies-form/add-currencies-form"
|
||||
|
||||
export const StoreAddCurrencies = () => {
|
||||
const { store, isLoading, isError, error } = useStore()
|
||||
const { store, isPending: isLoading, isError, error } = useStore()
|
||||
|
||||
if (isError) {
|
||||
throw error
|
||||
|
||||
+49
-17
@@ -5,6 +5,7 @@ import {
|
||||
CommandBar,
|
||||
Container,
|
||||
Heading,
|
||||
toast,
|
||||
usePrompt,
|
||||
} from "@medusajs/ui"
|
||||
import { keepPreviousData } from "@tanstack/react-query"
|
||||
@@ -31,7 +32,13 @@ export const StoreCurrencySection = ({ store }: StoreCurrencySectionProps) => {
|
||||
|
||||
const { searchParams, raw } = useCurrenciesTableQuery({ pageSize: PAGE_SIZE })
|
||||
|
||||
const { currencies, count, isLoading, isError, error } = useCurrencies(
|
||||
const {
|
||||
currencies,
|
||||
count,
|
||||
isPending: isLoading,
|
||||
isError,
|
||||
error,
|
||||
} = useCurrencies(
|
||||
{
|
||||
code: store.supported_currency_codes,
|
||||
...searchParams,
|
||||
@@ -56,8 +63,9 @@ export const StoreCurrencySection = ({ store }: StoreCurrencySectionProps) => {
|
||||
enableRowSelection: true,
|
||||
pageSize: PAGE_SIZE,
|
||||
meta: {
|
||||
currencyCodes: store.supported_currency_codes,
|
||||
storeId: store.id,
|
||||
currencyCodes: store.supported_currency_codes,
|
||||
defaultCurrencyCode: store.default_currency_code,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -81,18 +89,24 @@ export const StoreCurrencySection = ({ store }: StoreCurrencySectionProps) => {
|
||||
return
|
||||
}
|
||||
|
||||
await mutateAsync(
|
||||
{
|
||||
try {
|
||||
await mutateAsync({
|
||||
supported_currency_codes: store.supported_currency_codes.filter(
|
||||
(c) => !ids.includes(c)
|
||||
),
|
||||
},
|
||||
{
|
||||
onSuccess: () => {
|
||||
setRowSelection({})
|
||||
},
|
||||
}
|
||||
)
|
||||
})
|
||||
setRowSelection({})
|
||||
|
||||
toast.success(t("general.success"), {
|
||||
description: t("store.toast.currenciesRemoved"),
|
||||
dismissLabel: t("actions.close"),
|
||||
})
|
||||
} catch (e) {
|
||||
toast.error(t("general.error"), {
|
||||
description: e.message,
|
||||
dismissLabel: t("actions.close"),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (isError) {
|
||||
@@ -151,10 +165,12 @@ const CurrencyActions = ({
|
||||
storeId,
|
||||
currency,
|
||||
currencyCodes,
|
||||
defaultCurrencyCode,
|
||||
}: {
|
||||
storeId: string
|
||||
currency: CurrencyDTO
|
||||
currencyCodes: string[]
|
||||
defaultCurrencyCode: string
|
||||
}) => {
|
||||
const { mutateAsync } = useUpdateStore(storeId)
|
||||
|
||||
@@ -177,11 +193,23 @@ const CurrencyActions = ({
|
||||
return
|
||||
}
|
||||
|
||||
await mutateAsync({
|
||||
supported_currency_codes: currencyCodes.filter(
|
||||
(c) => c !== currency.code
|
||||
),
|
||||
})
|
||||
try {
|
||||
await mutateAsync({
|
||||
supported_currency_codes: currencyCodes.filter(
|
||||
(c) => c !== currency.code
|
||||
),
|
||||
})
|
||||
|
||||
toast.success(t("general.success"), {
|
||||
description: t("store.toast.currenciesRemoved"),
|
||||
dismissLabel: t("actions.close"),
|
||||
})
|
||||
} catch (e) {
|
||||
toast.error(t("general.error"), {
|
||||
description: e.message,
|
||||
dismissLabel: t("actions.close"),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -193,6 +221,7 @@ const CurrencyActions = ({
|
||||
icon: <Trash />,
|
||||
label: t("actions.remove"),
|
||||
onClick: handleRemove,
|
||||
disabled: currency.code === defaultCurrencyCode,
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -240,9 +269,11 @@ const useColumns = () => {
|
||||
columnHelper.display({
|
||||
id: "actions",
|
||||
cell: ({ row, table }) => {
|
||||
const { currencyCodes, storeId } = table.options.meta as {
|
||||
const { currencyCodes, storeId, defaultCurrencyCode } = table.options
|
||||
.meta as {
|
||||
currencyCodes: string[]
|
||||
storeId: string
|
||||
defaultCurrencyCode: string
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -250,6 +281,7 @@ const useColumns = () => {
|
||||
storeId={storeId}
|
||||
currency={row.original}
|
||||
currencyCodes={currencyCodes}
|
||||
defaultCurrencyCode={defaultCurrencyCode}
|
||||
/>
|
||||
)
|
||||
},
|
||||
|
||||
+18
@@ -3,6 +3,7 @@ import { Badge, Container, Heading, Text } from "@medusajs/ui"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import { ActionMenu } from "../../../../../components/common/action-menu"
|
||||
import { ExtendedStoreDTO } from "../../../../../types/api-responses"
|
||||
import { useRegion } from "../../../../../hooks/api/regions"
|
||||
|
||||
type StoreGeneralSectionProps = {
|
||||
store: ExtendedStoreDTO
|
||||
@@ -11,6 +12,10 @@ type StoreGeneralSectionProps = {
|
||||
export const StoreGeneralSection = ({ store }: StoreGeneralSectionProps) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const { region } = useRegion(store.default_region_id, undefined, {
|
||||
enabled: !!store.default_region_id,
|
||||
})
|
||||
|
||||
return (
|
||||
<Container className="divide-y p-0">
|
||||
<div className="flex items-center justify-between px-6 py-4">
|
||||
@@ -57,6 +62,19 @@ export const StoreGeneralSection = ({ store }: StoreGeneralSectionProps) => {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{region && (
|
||||
<div className="grid grid-cols-2 px-6 py-4">
|
||||
<Text size="small" leading="compact" weight="plus">
|
||||
{t("store.defaultRegion")}
|
||||
</Text>
|
||||
<div className="flex items-center gap-x-2">
|
||||
<Text size="small" leading="compact">
|
||||
{region.name}
|
||||
</Text>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -9,7 +9,12 @@ import { storeLoader } from "./loader"
|
||||
export const StoreDetail = () => {
|
||||
const initialData = useLoaderData() as Awaited<ReturnType<typeof storeLoader>>
|
||||
|
||||
const { store, isLoading, isError, error } = useStore({
|
||||
const {
|
||||
store,
|
||||
isPending: isLoading,
|
||||
isError,
|
||||
error,
|
||||
} = useStore({
|
||||
initialData,
|
||||
})
|
||||
|
||||
|
||||
+78
-9
@@ -1,5 +1,5 @@
|
||||
import { zodResolver } from "@hookform/resolvers/zod"
|
||||
import { Button, Input } from "@medusajs/ui"
|
||||
import { Button, Input, Select, toast } from "@medusajs/ui"
|
||||
import { useForm } from "react-hook-form"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import { z } from "zod"
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
} from "../../../../../components/route-modal"
|
||||
import { useUpdateStore } from "../../../../../hooks/api/store"
|
||||
import { ExtendedStoreDTO } from "../../../../../types/api-responses"
|
||||
import { useRegions } from "../../../../../hooks/api/regions"
|
||||
|
||||
type EditStoreFormProps = {
|
||||
store: ExtendedStoreDTO
|
||||
@@ -18,8 +19,8 @@ type EditStoreFormProps = {
|
||||
|
||||
const EditStoreSchema = z.object({
|
||||
name: z.string().min(1),
|
||||
// default_currency_code: z.string().optional(),
|
||||
// default_region_id: z.string().optional(),
|
||||
default_currency_code: z.string().optional(),
|
||||
default_region_id: z.string().optional(),
|
||||
// default_location_id: z.string().optional(),
|
||||
})
|
||||
|
||||
@@ -30,18 +31,32 @@ export const EditStoreForm = ({ store }: EditStoreFormProps) => {
|
||||
const form = useForm<z.infer<typeof EditStoreSchema>>({
|
||||
defaultValues: {
|
||||
name: store.name,
|
||||
default_region_id: store.default_region_id || undefined,
|
||||
default_currency_code: store.default_currency_code || undefined,
|
||||
},
|
||||
resolver: zodResolver(EditStoreSchema),
|
||||
})
|
||||
|
||||
const { mutateAsync, isPending } = useUpdateStore(store.id)
|
||||
|
||||
const { regions, isPending: isRegionsLoading } = useRegions({ limit: 999 })
|
||||
|
||||
const handleSubmit = form.handleSubmit(async (values) => {
|
||||
mutateAsync(values, {
|
||||
onSuccess: () => {
|
||||
handleSuccess()
|
||||
},
|
||||
})
|
||||
try {
|
||||
await mutateAsync(values)
|
||||
|
||||
handleSuccess()
|
||||
|
||||
toast.success(t("general.success"), {
|
||||
description: t("store.toast.update"),
|
||||
dismissLabel: t("actions.close"),
|
||||
})
|
||||
} catch (e) {
|
||||
toast.error(t("general.error"), {
|
||||
description: e.message,
|
||||
dismissLabel: t("actions.close"),
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
@@ -62,7 +77,61 @@ export const EditStoreForm = ({ store }: EditStoreFormProps) => {
|
||||
</Form.Item>
|
||||
)}
|
||||
/>
|
||||
{/* TODO: Add comboboxes for default region, location, and currency. `q` is currently missing on all v2 endpoints */}
|
||||
{/* TODO: Add comboboxes for default sales channel and location */}
|
||||
<Form.Field
|
||||
control={form.control}
|
||||
name="default_currency_code"
|
||||
render={({ field: { onChange, ...field } }) => {
|
||||
return (
|
||||
<Form.Item>
|
||||
<Form.Label>{t("store.defaultCurrency")}</Form.Label>
|
||||
<Form.Control>
|
||||
<Select {...field} onValueChange={onChange}>
|
||||
<Select.Trigger ref={field.ref}>
|
||||
<Select.Value />
|
||||
</Select.Trigger>
|
||||
<Select.Content>
|
||||
{store.supported_currency_codes.map((code) => (
|
||||
<Select.Item key={code} value={code}>
|
||||
{code.toUpperCase()}
|
||||
</Select.Item>
|
||||
))}
|
||||
</Select.Content>
|
||||
</Select>
|
||||
</Form.Control>
|
||||
</Form.Item>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<Form.Field
|
||||
control={form.control}
|
||||
name="default_region_id"
|
||||
render={({ field: { onChange, ...field } }) => {
|
||||
return (
|
||||
<Form.Item>
|
||||
<Form.Label>{t("store.defaultRegion")}</Form.Label>
|
||||
<Form.Control>
|
||||
<Select
|
||||
{...field}
|
||||
onValueChange={onChange}
|
||||
disabled={isRegionsLoading}
|
||||
>
|
||||
<Select.Trigger ref={field.ref}>
|
||||
<Select.Value />
|
||||
</Select.Trigger>
|
||||
<Select.Content>
|
||||
{(regions || []).map((region) => (
|
||||
<Select.Item key={region.id} value={region.id}>
|
||||
{region.name}
|
||||
</Select.Item>
|
||||
))}
|
||||
</Select.Content>
|
||||
</Select>
|
||||
</Form.Control>
|
||||
</Form.Item>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</RouteDrawer.Body>
|
||||
<RouteDrawer.Footer>
|
||||
|
||||
@@ -6,7 +6,7 @@ import { EditStoreForm } from "./components/edit-store-form/edit-store-form"
|
||||
|
||||
export const StoreEdit = () => {
|
||||
const { t } = useTranslation()
|
||||
const { store, isLoading, isError, error } = useStore()
|
||||
const { store, isPending: isLoading, isError, error } = useStore()
|
||||
|
||||
if (isError) {
|
||||
throw error
|
||||
|
||||
@@ -12,12 +12,12 @@ export const deleteStockLocationsStep = createStep(
|
||||
|
||||
return new StepResponse(void 0, input)
|
||||
},
|
||||
async (deletedLocaitonIds, { container }) => {
|
||||
if (!deletedLocaitonIds?.length) {
|
||||
async (deletedLocationIds, { container }) => {
|
||||
if (!deletedLocationIds?.length) {
|
||||
return
|
||||
}
|
||||
const service = container.resolve(ModuleRegistrationName.STOCK_LOCATION)
|
||||
|
||||
await service.restore(deletedLocaitonIds)
|
||||
await service.restore(deletedLocationIds)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
import { BigNumberRawValue } from "@medusajs/types"
|
||||
import { BigNumber, MikroOrmBigNumberProperty } from "@medusajs/utils"
|
||||
import {
|
||||
BigNumber,
|
||||
MikroOrmBigNumberProperty,
|
||||
Searchable,
|
||||
} from "@medusajs/utils"
|
||||
import { Entity, PrimaryKey, Property } from "@mikro-orm/core"
|
||||
|
||||
@Entity({ tableName: "currency" })
|
||||
class Currency {
|
||||
@Searchable()
|
||||
@PrimaryKey({ columnType: "text" })
|
||||
code!: string
|
||||
|
||||
@@ -13,6 +18,7 @@ class Currency {
|
||||
@Property({ columnType: "text" })
|
||||
symbol_native: string
|
||||
|
||||
@Searchable()
|
||||
@Property({ columnType: "text" })
|
||||
name: string
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ export const AdminGetCurrenciesParams = createFindParams({
|
||||
limit: 50,
|
||||
}).merge(
|
||||
z.object({
|
||||
q: z.string().optional(),
|
||||
code: z.union([z.string(), z.array(z.string())]).optional(),
|
||||
$and: z.lazy(() => AdminGetCurrenciesParams.array()).optional(),
|
||||
$or: z.lazy(() => AdminGetCurrenciesParams.array()).optional(),
|
||||
|
||||
Reference in New Issue
Block a user