Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(dashboard,icons,types,js-sdk): add providers to location UI #8328

Merged
merged 6 commits into from
Jul 30, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions packages/admin-next/dashboard/src/hooks/api/stock-locations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { HttpTypes } from "@medusajs/types"
import { sdk } from "../../lib/client"
import { queryClient } from "../../lib/query-client"
import { queryKeysFactory } from "../../lib/query-key-factory"
import { fulfillmentProvidersQueryKeys } from "./fulfillment-providers"

const STOCK_LOCATIONS_QUERY_KEY = "stock_locations" as const
export const stockLocationsQueryKeys = queryKeysFactory(
Expand Down Expand Up @@ -175,3 +176,31 @@ export const useCreateStockLocationFulfillmentSet = (
...options,
})
}

export const useUpdateStockLocationFulfillmentProviders = (
id: string,
options?: UseMutationOptions<
HttpTypes.AdminStockLocationResponse,
FetchError,
HttpTypes.AdminBatchLink
>
) => {
return useMutation({
mutationFn: (payload) =>
sdk.admin.stockLocation.updateFulfillmentProviders(id, payload),
onSuccess: async (data, variables, context) => {
await queryClient.invalidateQueries({
queryKey: stockLocationsQueryKeys.details(),
})
await queryClient.invalidateQueries({
queryKey: stockLocationsQueryKeys.lists(),
})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: think we can skip invalidating the lists key for this one

await queryClient.invalidateQueries({
queryKey: fulfillmentProvidersQueryKeys.lists(),
})

options?.onSuccess?.(data, variables, context)
},
...options,
})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { HttpTypes } from "@medusajs/types"
import { createColumnHelper } from "@tanstack/react-table"
import { useMemo } from "react"
import { useTranslation } from "react-i18next"
import {
TextCell,
TextHeader,
} from "../../../components/table/table-cells/common/text-cell"

const columnHelper = createColumnHelper<HttpTypes.AdminFulfillmentProvider>()

export const useFulfillmentProviderTableColumns = () => {
const { t } = useTranslation()

return useMemo(
() => [
columnHelper.accessor("id", {
header: () => <TextHeader text={"Provider"} />,
cell: ({ getValue }) => <TextCell text={getValue()} />,
}),
],
[t]
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { HttpTypes } from "@medusajs/types"
import { useQueryParams } from "../../use-query-params"

type UseFulfillmentProviderTableQueryProps = {
prefix?: string
pageSize?: number
}

export const useFulfillmentProvidersTableQuery = ({
prefix,
pageSize = 20,
}: UseFulfillmentProviderTableQueryProps) => {
const queryObject = useQueryParams(
["offset", "q", "stock_location_id"],
prefix
)

const { offset, q, stock_location_id } = queryObject

const searchParams: HttpTypes.AdminFulfillmentProviderListParams = {
limit: pageSize,
offset: offset ? Number(offset) : 0,
stock_location_id,
q,
}

return {
searchParams,
raw: queryObject,
}
}
8 changes: 8 additions & 0 deletions packages/admin-next/dashboard/src/i18n/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -998,6 +998,14 @@
"delete": {
"confirmation": "You are about to delete the stock location {{name}}. This action cannot be undone."
},
"fulfillmentProviders": {
"header": "Fulfillment Providers",
"label": "Connected fulfillment providers",
"connectedTo": "Connected to {{count}} of {{total}} fulfillment providers",
"noProviders": "This Stock Location is not connected to any fulfillment providers.",
"action": "Connect Providers",
"successToast": "Fulfillment providers for stock location were successfully updated."
},
"fulfillmentSets": {
"pickup": {
"header": "Pickup"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -859,6 +859,13 @@ export const RouteMap: RouteObject[] = [
lazy: () =>
import("../../routes/locations/location-sales-channels"),
},
{
path: "fulfillment-providers",
lazy: () =>
import(
"../../routes/locations/location-fulfillment-providers"
),
},
{
path: "fulfillment-set/:fset_id",
children: [
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./location-fulfillment-providers-section"
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { HandTruck, PencilSquare } from "@medusajs/icons"
import { HttpTypes } from "@medusajs/types"
import { Container, Heading, Text } from "@medusajs/ui"
import { useTranslation } from "react-i18next"

import { ActionMenu } from "../../../../../components/common/action-menu"
import { NoRecords } from "../../../../../components/common/empty-table-content"
import { IconAvatar } from "../../../../../components/common/icon-avatar"
import { ListSummary } from "../../../../../components/common/list-summary"
import { useFulfillmentProviders } from "../../../../../hooks/api"

type LocationsFulfillmentProvidersSectionProps = {
location: HttpTypes.AdminStockLocation
}

function LocationsFulfillmentProvidersSection({
location,
}: LocationsFulfillmentProvidersSectionProps) {
const { t } = useTranslation()
const { count } = useFulfillmentProviders({
limit: 1,
fields: "id",
})

return (
<Container className="flex flex-col px-6 py-4">
<div className="flex items-center justify-between">
<Heading level="h2">
{t("stockLocations.fulfillmentProviders.header")}
</Heading>

<ActionMenu
groups={[
{
actions: [
{
label: t("actions.edit"),
to: "fulfillment-providers",
icon: <PencilSquare />,
},
],
},
]}
/>
</div>

{location?.fulfillment_providers?.length ? (
<div className="flex flex-col gap-y-4 pt-4">
<div className="grid grid-cols-[28px_1fr] items-center gap-x-3">
<IconAvatar>
<HandTruck className="text-ui-fg-subtle" />
</IconAvatar>

<ListSummary
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: should the "+1 more" be displayed inline without spacing in between and right alignment?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added a comment below that changes this whole thing.

n={2}
className="text-ui-fg-base"
inline
list={location?.fulfillment_providers?.map((fp) => fp.id) ?? []}
/>
</div>

<Text className="text-ui-fg-subtle" size="small" leading="compact">
{t("stockLocations.fulfillmentProviders.connectedTo", {
count: location?.fulfillment_providers?.length,
total: count,
})}
</Text>
</div>
) : (
<NoRecords
className="h-fit pb-2 pt-6 text-center"
action={{
label: t("stockLocations.fulfillmentProviders.action"),
to: "fulfillment-providers",
}}
message={t("stockLocations.fulfillmentProviders.noProviders")}
/>
)}
</Container>
)
}

export default LocationsFulfillmentProvidersSection
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export const detailsFields =
"name,*sales_channels,*address,fulfillment_sets.type,fulfillment_sets.name,*fulfillment_sets.service_zones.geo_zones,*fulfillment_sets.service_zones,*fulfillment_sets.service_zones.shipping_options,*fulfillment_sets.service_zones.shipping_options.rules,*fulfillment_sets.service_zones.shipping_options.shipping_profile"
"name,*sales_channels,*address,fulfillment_sets.type,fulfillment_sets.name,*fulfillment_sets.service_zones.geo_zones,*fulfillment_sets.service_zones,*fulfillment_sets.service_zones.shipping_options,*fulfillment_sets.service_zones.shipping_options.rules,*fulfillment_sets.service_zones.shipping_options.shipping_profile,*fulfillment_providers"
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import after from "virtual:medusa/widgets/location/details/after"
import before from "virtual:medusa/widgets/location/details/before"
import sideAfter from "virtual:medusa/widgets/location/details/side/after"
import sideBefore from "virtual:medusa/widgets/location/details/side/before"
import LocationsFulfillmentProvidersSection from "./components/location-fulfillment-providers-section/location-fulfillment-providers-section"
import { detailsFields } from "./const"

export const LocationDetail = () => {
Expand All @@ -23,15 +24,7 @@ export const LocationDetail = () => {
isPending: isLoading,
isError,
error,
} = useStockLocation(
location_id!,
{
fields: detailsFields,
},
{
initialData,
}
)
} = useStockLocation(location_id!, { fields: detailsFields }, { initialData })

// TODO: Move to loading.tsx and set as Suspense fallback for the route
if (isLoading || !location) {
Expand Down Expand Up @@ -73,7 +66,10 @@ export const LocationDetail = () => {
</div>
)
})}

<LocationsSalesChannelsSection location={location} />
<LocationsFulfillmentProvidersSection location={location} />

{sideAfter.widgets.map((w, i) => {
return (
<div key={i}>
Expand Down
Loading
Loading