diff --git a/.changeset/honest-toys-decide.md b/.changeset/honest-toys-decide.md new file mode 100644 index 00000000000..50e97618ca3 --- /dev/null +++ b/.changeset/honest-toys-decide.md @@ -0,0 +1,5 @@ +--- +"saleor-dashboard": minor +--- + +Migrate product variant page to new macaw diff --git a/cypress/support/pages/catalog/products/VariantsPage.js b/cypress/support/pages/catalog/products/VariantsPage.js index 4b1ee2f575c..d29dc9a18bc 100644 --- a/cypress/support/pages/catalog/products/VariantsPage.js +++ b/cypress/support/pages/catalog/products/VariantsPage.js @@ -71,7 +71,13 @@ export function fillUpVariantDetails({ price, variantName, }) { + if (variantName) { + cy.get(VARIANTS_SELECTORS.variantNameInput).type(variantName, { + force: true, + }); + } selectAttributeWithType({ attributeType, attributeName }); + cy.get(PRICE_LIST.priceInput) .each(input => { cy.wrap(input).type(price, { force: true }); @@ -80,9 +86,6 @@ export function fillUpVariantDetails({ .each(input => { cy.wrap(input).type(costPrice, { force: true }); }); - if (variantName) { - cy.get(VARIANTS_SELECTORS.variantNameInput).type(variantName); - } if (sku) { cy.get(VARIANTS_SELECTORS.skuTextField).click({ force: true }).type(sku); } diff --git a/locale/defaultMessages.json b/locale/defaultMessages.json index 3405434cc51..3ec32a0d571 100644 --- a/locale/defaultMessages.json +++ b/locale/defaultMessages.json @@ -3177,10 +3177,6 @@ "KN7zKn": { "string": "Error" }, - "KQSONM": { - "context": "tabel column header", - "string": "Cost" - }, "KRqgfo": { "string": "User is out of your permissions scope" }, @@ -3460,6 +3456,10 @@ "context": "customer details, header", "string": "{fullName} Details" }, + "MwfSVA": { + "context": "input helper text", + "string": "Customers can not add quantities to a single cart above the limit when value is provided." + }, "MxhVZv": { "string": "Are you sure you want to delete collection's image?" }, @@ -7147,10 +7147,6 @@ "context": "WarehousesSection select field add text", "string": "Add New Warehouse" }, - "n3+6w5": { - "context": "input helper text", - "string": "Your customer won't be allowed to buy bigger quantity per checkout than shown here." - }, "n5vskv": { "context": "customer's address book, header", "string": "{fullName}'s Address Book" @@ -8386,6 +8382,9 @@ "vprU7C": { "string": "Select visible order channels" }, + "vuKrlW": { + "string": "Stock" + }, "vwMO04": { "context": "draft order", "string": "Created" diff --git a/src/components/Datagrid/customCells/Money/MoneyCell.tsx b/src/components/Datagrid/customCells/Money/MoneyCell.tsx index 8aa1e60c215..f304123b2e3 100644 --- a/src/components/Datagrid/customCells/Money/MoneyCell.tsx +++ b/src/components/Datagrid/customCells/Money/MoneyCell.tsx @@ -65,29 +65,29 @@ export const moneyCellRenderer = ( return true; } + const codeFormatter = new Intl.NumberFormat(locale, { + style: "currency", + currencyDisplay: "code", + currency, + }); + + const symbolFormatter = new Intl.NumberFormat(locale, { + style: "currency", + currencyDisplay: "symbol", + currency, + }); + + if (!("formatRangeToParts" in codeFormatter)) { + return true; + } + const format = isRange - ? new Intl.NumberFormat(locale, { - style: "currency", - currencyDisplay: "code", - currency, - }).formatRangeToParts(value[0], value[1]) - : new Intl.NumberFormat(locale, { - style: "currency", - currencyDisplay: "code", - currency, - }).formatToParts(displayValue); + ? codeFormatter.formatRangeToParts(value[0], value[1]) + : codeFormatter.formatToParts(displayValue); const shortFormat = isRange - ? new Intl.NumberFormat(locale, { - style: "currency", - currencyDisplay: "symbol", - currency, - }).formatRangeToParts(value[0], value[1]) - : new Intl.NumberFormat(locale, { - style: "currency", - currencyDisplay: "symbol", - currency, - }).formatToParts(displayValue); + ? symbolFormatter.formatRangeToParts(value[0], value[1]) + : symbolFormatter.formatToParts(displayValue); // TODO: replace with macaw-ui theme font weight values ctx.font = `550 ${theme.baseFontStyle} ${theme.fontFamily}`; diff --git a/src/components/Divider/Divider.tsx b/src/components/Divider/Divider.tsx new file mode 100644 index 00000000000..26ce959b0d2 --- /dev/null +++ b/src/components/Divider/Divider.tsx @@ -0,0 +1,15 @@ +import { Box, BoxProps } from "@saleor/macaw-ui/next"; +import React from "react"; + +export const Divider = (props: BoxProps) => { + return ( + + ); +}; diff --git a/src/components/Divider/index.ts b/src/components/Divider/index.ts new file mode 100644 index 00000000000..dde73a62ccb --- /dev/null +++ b/src/components/Divider/index.ts @@ -0,0 +1 @@ +export * from "./Divider"; diff --git a/src/components/MediaTile/MediaTile.tsx b/src/components/MediaTile/MediaTile.tsx index 24e8ab5f6ba..22050b3d7a0 100644 --- a/src/components/MediaTile/MediaTile.tsx +++ b/src/components/MediaTile/MediaTile.tsx @@ -39,8 +39,13 @@ const useStyles = makeStyles( top: 0, width: 148, }, + disableOverlay: { + "&$mediaOverlay": { + display: "none !important", + }, + }, mediaOverlayShadow: { - "&mediaOverlay": { + $mediaOverlay: { alignItems: "center", display: "flex", justifyContent: "center", @@ -76,6 +81,7 @@ interface MediaTileBaseProps { type?: string; oembedData?: string; }; + disableOverlay?: boolean; loading?: boolean; onDelete?: () => void; onEdit?: (event: React.ChangeEvent) => void; @@ -94,7 +100,14 @@ export type MediaTileProps = MediaTileBaseProps & ); const MediaTile: React.FC = props => { - const { loading, onDelete, onEdit, editHref, media } = props; + const { + loading, + onDelete, + onEdit, + editHref, + media, + disableOverlay = false, + } = props; const classes = useStyles(props); const parsedMediaOembedData = media?.oembedData ? JSON.parse(media.oembedData) @@ -106,6 +119,7 @@ const MediaTile: React.FC = props => {
{loading ? ( diff --git a/src/components/SortableTable/SortableHandle.tsx b/src/components/SortableTable/SortableHandle.tsx index 7009e2e2382..74b620a928f 100644 --- a/src/components/SortableTable/SortableHandle.tsx +++ b/src/components/SortableTable/SortableHandle.tsx @@ -1,5 +1,6 @@ import { TableCell } from "@material-ui/core"; -import { DragIcon, makeStyles } from "@saleor/macaw-ui"; +import { makeStyles } from "@saleor/macaw-ui"; +import { GripIcon } from "@saleor/macaw-ui/next"; import React from "react"; import { SortableHandle as SortableHandleHoc } from "react-sortable-hoc"; @@ -22,7 +23,7 @@ const SortableHandle = SortableHandleHoc(() => { return ( - + ); }); diff --git a/src/components/TableCellAvatar/Avatar.tsx b/src/components/TableCellAvatar/Avatar.tsx index 1b3ee1e0db9..ccde81e40a1 100644 --- a/src/components/TableCellAvatar/Avatar.tsx +++ b/src/components/TableCellAvatar/Avatar.tsx @@ -13,6 +13,7 @@ export interface AvatarProps { avatarProps?: string; children?: React.ReactNode | React.ReactNode[]; badge?: React.ReactNode; + className?: string; } const Avatar: React.FC = ({ @@ -22,12 +23,13 @@ const Avatar: React.FC = ({ thumbnail, avatarProps, badge, + className, }) => { const classes = useAvatarStyles(); return (
diff --git a/src/components/TableCellAvatar/TableCellAvatar.tsx b/src/components/TableCellAvatar/TableCellAvatar.tsx index 30031ec0bda..c60862cbdec 100644 --- a/src/components/TableCellAvatar/TableCellAvatar.tsx +++ b/src/components/TableCellAvatar/TableCellAvatar.tsx @@ -10,10 +10,11 @@ interface TableCellAvatarProps extends TableCellProps, Omit { className?: string; + avatarClassName?: string; } const TableCellAvatar: React.FC = props => { - const { className, ...rest } = props; + const { className, avatarClassName, ...rest } = props; const classes = useStyles(props); @@ -23,7 +24,7 @@ const TableCellAvatar: React.FC = props => { data-test-id="table-cell-avatar" {...rest} > - + ); }; diff --git a/src/fragments/products.ts b/src/fragments/products.ts index fd60743123d..afb2dac8979 100644 --- a/src/fragments/products.ts +++ b/src/fragments/products.ts @@ -330,7 +330,7 @@ export const fragmentVariant = gql` sku media { id - url + url(size: 200) type oembedData } diff --git a/src/graphql/hooks.generated.ts b/src/graphql/hooks.generated.ts index af2bde8465e..e6c74bcb415 100644 --- a/src/graphql/hooks.generated.ts +++ b/src/graphql/hooks.generated.ts @@ -2589,7 +2589,7 @@ export const ProductVariantFragmentDoc = gql` sku media { id - url + url(size: 200) type oembedData } diff --git a/src/orders/components/OrderSendRefundPage/components/TransactionCard.tsx b/src/orders/components/OrderSendRefundPage/components/TransactionCard.tsx index c8739da167e..a2638c182cc 100644 --- a/src/orders/components/OrderSendRefundPage/components/TransactionCard.tsx +++ b/src/orders/components/OrderSendRefundPage/components/TransactionCard.tsx @@ -57,7 +57,7 @@ export const TransactionCard: React.FC = ({ const id = useId(); const user = useUser(); - const isStaffUser = hasPermissions(user?.user?.userPermissions, [ + const isStaffUser = hasPermissions(user?.user?.userPermissions ?? [], [ PermissionEnum.MANAGE_STAFF, ]); diff --git a/src/orders/views/OrderDetails/OrderDetails.tsx b/src/orders/views/OrderDetails/OrderDetails.tsx index d5a13ee21b4..de8150aad07 100644 --- a/src/orders/views/OrderDetails/OrderDetails.tsx +++ b/src/orders/views/OrderDetails/OrderDetails.tsx @@ -50,7 +50,7 @@ export const OrderDetails: React.FC = ({ id, params }) => { const intl = useIntl(); const user = useUser(); - const isStaffUser = hasPermissions(user?.user?.userPermissions, [ + const isStaffUser = hasPermissions(user?.user?.userPermissions ?? [], [ PermissionEnum.MANAGE_STAFF, ]); diff --git a/src/products/components/ProductStocks/ProductStocks.tsx b/src/products/components/ProductStocks/ProductStocks.tsx index eba80274c92..39ca6704a3c 100644 --- a/src/products/components/ProductStocks/ProductStocks.tsx +++ b/src/products/components/ProductStocks/ProductStocks.tsx @@ -17,8 +17,6 @@ import { Dropdown, Input, List, - PlusIcon, - sprinkles, Text, TrashBinIcon, vars, @@ -118,29 +116,31 @@ export const ProductStocks: React.FC = ({ /> - - - onFormDataChange({ target: { name: "trackInventory", value } }) - } - > - - - - - - - - - + + + + onFormDataChange({ target: { name: "trackInventory", value } }) + } + > + + + + + + - + + + + + - - + + {!productVariantChannelListings?.length && ( @@ -175,124 +175,114 @@ export const ProductStocks: React.FC = ({ )} - - {productVariantChannelListings?.length > 0 && warehouses?.length > 0 && ( - - - - - - - - - - - - - - - - - - - - - - - {renderCollection(stocks, (stock, index) => { - const handleQuantityChange = createNonNegativeValueChangeHandler( - event => onChange(stock.id, event.target.value), - ); - - return ( - + {productVariantChannelListings?.length > 0 && + warehouses?.length > 0 && + stocks?.length > 0 && ( +
+ + - {stock.label} + + + - - {stock.data?.quantityAllocated || 0} + + + + - - - stocks.length === index + 1 && - handleStockInputFocus(input) - } - /> - - -
- )} + return ( + + + {stock.label} + + + {stock.data?.quantityAllocated || 0} + + + + stocks.length === index + 1 && + handleStockInputFocus(input) + } + /> + + + + + + + + + {warehousesToAssign.map(warehouse => ( + + handleWarehouseStockAdd(warehouse.id)} + > + {warehouse.name} + + + ))} + + + + + )} + ); }; diff --git a/src/products/components/ProductStocks/messages.ts b/src/products/components/ProductStocks/messages.ts index 01ac9b62761..88ecdac1e49 100644 --- a/src/products/components/ProductStocks/messages.ts +++ b/src/products/components/ProductStocks/messages.ts @@ -11,6 +11,10 @@ export const messages = defineMessages({ defaultMessage: "SKU (Stock Keeping Unit)", description: "input label", }, + stock: { + id: "vuKrlW", + defaultMessage: "Stock", + }, variantInPreorder: { id: "eAFU/E", defaultMessage: "Variant currently in preorder", diff --git a/src/products/components/ProductVariantChannels/ChannelsAvailabilityCard/AvailabilityCard.tsx b/src/products/components/ProductVariantChannels/ChannelsAvailabilityCard/AvailabilityCard.tsx index a5145066632..4b7c519e4bc 100644 --- a/src/products/components/ProductVariantChannels/ChannelsAvailabilityCard/AvailabilityCard.tsx +++ b/src/products/components/ProductVariantChannels/ChannelsAvailabilityCard/AvailabilityCard.tsx @@ -1,50 +1,34 @@ +import { Divider } from "@dashboard/components/Divider"; import React from "react"; -import { useIntl } from "react-intl"; -import { variantDetailsChannelsAvailabilityCardMessages as messages } from "./../messages"; import { Channel, ProductChannelListing } from "./../types"; -import { ChannelsList } from "./ChannelsList"; import { ChannelsListItem } from "./ChannelsListItem"; -import { NotAvailable } from "./NotAvailable"; import CardContainer from "./VariantDetailsChannelsAvailabilityCardContainer"; interface AvailabilityCardProps { items: Channel[]; productChannelListings: ProductChannelListing; - availabilityCount: Record; } export const AvailabilityCard: React.FC = ({ - availabilityCount, items, productChannelListings, children, }) => { - const intl = useIntl(); - const channelListSummary = intl.formatMessage( - messages.subtitle, - availabilityCount, - ); - if (items.length === 0) { - return ( - - - - ); + return {}; } return ( - - {items.map(channel => ( - - ))} - + {items.map(channel => ( + + ))} + ); }; diff --git a/src/products/components/ProductVariantChannels/ChannelsAvailabilityCard/CardSkeleton.tsx b/src/products/components/ProductVariantChannels/ChannelsAvailabilityCard/CardSkeleton.tsx index 5e53fd386b7..a894e498f57 100644 --- a/src/products/components/ProductVariantChannels/ChannelsAvailabilityCard/CardSkeleton.tsx +++ b/src/products/components/ProductVariantChannels/ChannelsAvailabilityCard/CardSkeleton.tsx @@ -1,13 +1,11 @@ +import { DashboardCard } from "@dashboard/components/Card"; import Skeleton from "@dashboard/components/Skeleton"; -import { CardContent } from "@material-ui/core"; import React from "react"; -import CardContainer from "./VariantDetailsChannelsAvailabilityCardContainer"; - export const CardSkeleton: React.FC = () => ( - - + + - - + + ); diff --git a/src/products/components/ProductVariantChannels/ChannelsAvailabilityCard/ChannelsList.tsx b/src/products/components/ProductVariantChannels/ChannelsAvailabilityCard/ChannelsList.tsx index a018431b27c..858e83ed49a 100644 --- a/src/products/components/ProductVariantChannels/ChannelsAvailabilityCard/ChannelsList.tsx +++ b/src/products/components/ProductVariantChannels/ChannelsAvailabilityCard/ChannelsList.tsx @@ -18,7 +18,7 @@ export const ChannelsList: React.FC = ({ paddingBottom: 8, })} > - + {summary} diff --git a/src/products/components/ProductVariantChannels/ChannelsAvailabilityCard/ChannelsListItem.tsx b/src/products/components/ProductVariantChannels/ChannelsAvailabilityCard/ChannelsListItem.tsx index dcafe8210c9..ecc9d31d3a3 100644 --- a/src/products/components/ProductVariantChannels/ChannelsAvailabilityCard/ChannelsListItem.tsx +++ b/src/products/components/ProductVariantChannels/ChannelsAvailabilityCard/ChannelsListItem.tsx @@ -1,6 +1,8 @@ // @ts-strict-ignore +import { DashboardCard } from "@dashboard/components/Card"; +import { Divider } from "@dashboard/components/Divider"; import useDateLocalize from "@dashboard/hooks/useDateLocalize"; -import { CardContent, Divider, Typography } from "@material-ui/core"; +import { Text } from "@saleor/macaw-ui/next"; import React from "react"; import { useIntl } from "react-intl"; @@ -38,19 +40,22 @@ export const ChannelsListItem: React.FC = ({ return ( - - + {name} - - + {getItemSubtitle(id)} - - + + ); }; diff --git a/src/products/components/ProductVariantChannels/ChannelsAvailabilityCard/CreateVariantTitle.tsx b/src/products/components/ProductVariantChannels/ChannelsAvailabilityCard/CreateVariantTitle.tsx index b3c159839e2..a5d494976e0 100644 --- a/src/products/components/ProductVariantChannels/ChannelsAvailabilityCard/CreateVariantTitle.tsx +++ b/src/products/components/ProductVariantChannels/ChannelsAvailabilityCard/CreateVariantTitle.tsx @@ -1,5 +1,5 @@ -import { Button } from "@dashboard/components/Button"; -import CardTitle from "@dashboard/components/CardTitle"; +import { DashboardCard } from "@dashboard/components/Card"; +import { Accordion, Box, Button, Text } from "@saleor/macaw-ui/next"; import React from "react"; import { useIntl } from "react-intl"; @@ -7,26 +7,57 @@ import { variantDetailsChannelsAvailabilityCardMessages as messages } from "./.. interface CreateVariantTitleProps { onManageClick: () => void; + disabled: boolean; + availabilityCount: Record; + isEmpty: boolean; } export const CreateVariantTitle: React.FC = ({ onManageClick, + disabled, + availabilityCount, + isEmpty, }) => { const intl = useIntl(); + const getCaptionText = () => { + if (isEmpty) { + return intl.formatMessage(messages.noItemsAvailable); + } + + return intl.formatMessage(messages.subtitle, availabilityCount); + }; + return ( - - {intl.formatMessage(messages.manageButtonText)} - - } - /> + + + + + {intl.formatMessage(messages.title)} + + {getCaptionText()} + + + + + + + + + + + ); }; diff --git a/src/products/components/ProductVariantChannels/ChannelsAvailabilityCard/NotAvailable.tsx b/src/products/components/ProductVariantChannels/ChannelsAvailabilityCard/NotAvailable.tsx deleted file mode 100644 index 2750426b43f..00000000000 --- a/src/products/components/ProductVariantChannels/ChannelsAvailabilityCard/NotAvailable.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { CardContent, Typography } from "@material-ui/core"; -import React from "react"; -import { useIntl } from "react-intl"; - -import { variantDetailsChannelsAvailabilityCardMessages as messages } from "./../messages"; - -export const NotAvailable: React.FC = () => { - const intl = useIntl(); - - return ( - - - {intl.formatMessage(messages.noItemsAvailable)} - - - ); -}; diff --git a/src/products/components/ProductVariantChannels/ChannelsAvailabilityCard/VariantDetailsChannelsAvailabilityCardContainer.tsx b/src/products/components/ProductVariantChannels/ChannelsAvailabilityCard/VariantDetailsChannelsAvailabilityCardContainer.tsx index 195a5710877..01e53c49df5 100644 --- a/src/products/components/ProductVariantChannels/ChannelsAvailabilityCard/VariantDetailsChannelsAvailabilityCardContainer.tsx +++ b/src/products/components/ProductVariantChannels/ChannelsAvailabilityCard/VariantDetailsChannelsAvailabilityCardContainer.tsx @@ -1,6 +1,5 @@ -import CardSpacer from "@dashboard/components/CardSpacer"; -import CardTitle from "@dashboard/components/CardTitle"; -import { Card } from "@material-ui/core"; +import { DashboardCard } from "@dashboard/components/Card"; +import { Accordion } from "@saleor/macaw-ui/next"; import React from "react"; import { FormattedMessage } from "react-intl"; @@ -15,13 +14,18 @@ const VariantDetailsChannelsAvailabilityCardContainer: React.FC< VariantDetailsChannelsAvailabilityCardContainerProps > = ({ children, cardTitle }) => ( <> - - {cardTitle || ( - } /> - )} - {children} - - + + + + {cardTitle || ( + + + + )} + {children} + + + ); diff --git a/src/products/components/ProductVariantChannels/ChannelsAvailabilityCard/index.tsx b/src/products/components/ProductVariantChannels/ChannelsAvailabilityCard/index.tsx index 1c97127e732..cfd0ef5adec 100644 --- a/src/products/components/ProductVariantChannels/ChannelsAvailabilityCard/index.tsx +++ b/src/products/components/ProductVariantChannels/ChannelsAvailabilityCard/index.tsx @@ -13,11 +13,13 @@ import { CreateVariantTitle } from "./CreateVariantTitle"; interface VariantDetailsChannelsAvailabilityCardProps { variant: Variant; onManageClick?: () => void; + disabled: boolean; } interface ProductDetailsChannelsAvailabilityCardProps { product: Product; onManageClick?: () => void; + disabled: boolean; } interface WrapperProps { @@ -37,15 +39,19 @@ const Wrapper: React.FC = ({ item, children }) => { export const VariantDetailsChannelsAvailabilityCard: React.FC< VariantDetailsChannelsAvailabilityCardProps -> = ({ variant, onManageClick }) => ( +> = ({ variant, onManageClick, disabled }) => ( {({ channels }) => ( - + )} @@ -53,15 +59,19 @@ export const VariantDetailsChannelsAvailabilityCard: React.FC< export const ProductDetailsChannelsAvailabilityCard: React.FC< ProductDetailsChannelsAvailabilityCardProps -> = ({ product, onManageClick }) => ( +> = ({ product, onManageClick, disabled }) => ( {({ channels }) => ( - + )} diff --git a/src/products/components/ProductVariantCheckoutSettings/ProductVariantCheckoutSettings.tsx b/src/products/components/ProductVariantCheckoutSettings/ProductVariantCheckoutSettings.tsx index a59104a5710..c25890cb111 100644 --- a/src/products/components/ProductVariantCheckoutSettings/ProductVariantCheckoutSettings.tsx +++ b/src/products/components/ProductVariantCheckoutSettings/ProductVariantCheckoutSettings.tsx @@ -1,9 +1,9 @@ -import CardTitle from "@dashboard/components/CardTitle"; +import { DashboardCard } from "@dashboard/components/Card"; import PreviewPill from "@dashboard/components/PreviewPill"; import { ProductErrorFragment } from "@dashboard/graphql"; import { FormChange } from "@dashboard/hooks/useForm"; import { getFormErrors } from "@dashboard/utils/errors"; -import { Card, CardContent, TextField } from "@material-ui/core"; +import { Input } from "@saleor/macaw-ui/next"; import React from "react"; import { useIntl } from "react-intl"; @@ -30,21 +30,17 @@ const ProductVariantCheckoutSettings: React.FC< const formErrors = getFormErrors(["quantityLimitPerCustomer"], errors); return ( - - - {intl.formatMessage(messages.checkoutLimits)} - - - } - /> - - + + {intl.formatMessage(messages.checkoutLimits)} + + + + - - + + ); }; diff --git a/src/products/components/ProductVariantCheckoutSettings/messages.ts b/src/products/components/ProductVariantCheckoutSettings/messages.ts index 754eac2128e..49a34c4cdb9 100644 --- a/src/products/components/ProductVariantCheckoutSettings/messages.ts +++ b/src/products/components/ProductVariantCheckoutSettings/messages.ts @@ -12,9 +12,9 @@ export const messages = defineMessages({ description: "input label", }, checkoutLimitsDescription: { - id: "n3+6w5", + id: "MwfSVA", defaultMessage: - "Your customer won't be allowed to buy bigger quantity per checkout than shown here.", + "Customers can not add quantities to a single cart above the limit when value is provided.", description: "input helper text", }, }); diff --git a/src/products/components/ProductVariantCreatePage/ProductVariantCreatePage.tsx b/src/products/components/ProductVariantCreatePage/ProductVariantCreatePage.tsx index f33ef6c63f9..f7b1365a69b 100644 --- a/src/products/components/ProductVariantCreatePage/ProductVariantCreatePage.tsx +++ b/src/products/components/ProductVariantCreatePage/ProductVariantCreatePage.tsx @@ -180,7 +180,7 @@ const ProductVariantCreatePage: React.FC = ({ const errors = [...apiErrors, ...validationErrors]; return ( - + @@ -202,6 +202,7 @@ const ProductVariantCreatePage: React.FC = ({ /> diff --git a/src/products/components/ProductVariantMedia/ProductVariantMedia.tsx b/src/products/components/ProductVariantMedia/ProductVariantMedia.tsx index e88b1792cc7..9da91270899 100644 --- a/src/products/components/ProductVariantMedia/ProductVariantMedia.tsx +++ b/src/products/components/ProductVariantMedia/ProductVariantMedia.tsx @@ -1,11 +1,9 @@ // @ts-strict-ignore -import { Button } from "@dashboard/components/Button"; -import CardTitle from "@dashboard/components/CardTitle"; +import { DashboardCard } from "@dashboard/components/Card"; +import MediaTile from "@dashboard/components/MediaTile"; import Skeleton from "@dashboard/components/Skeleton"; import { ProductMediaFragment } from "@dashboard/graphql"; -import { Card, CardContent, Typography } from "@material-ui/core"; -import { makeStyles } from "@saleor/macaw-ui"; -import { vars } from "@saleor/macaw-ui/next"; +import { Box, Button, Text } from "@saleor/macaw-ui/next"; import React from "react"; import { defineMessages, useIntl } from "react-intl"; @@ -27,37 +25,6 @@ const messages = defineMessages({ }, }); -const useStyles = makeStyles( - theme => ({ - gridElement: { - "& img": { - width: "100%", - }, - }, - helpText: { - gridColumnEnd: "span 4", - }, - image: { - objectFit: "contain", - width: "100%", - }, - imageContainer: { - background: "#ffffff", - border: `1px solid ${vars.colors.border.neutralPlain}`, - borderRadius: theme.spacing(), - height: theme.spacing(17.5), - marginBottom: theme.spacing(2), - padding: theme.spacing(2), - }, - root: { - display: "grid", - gridColumnGap: theme.spacing(2), - gridTemplateColumns: "repeat(4, 1fr)", - }, - }), - { name: "ProductVariantMedia" }, -); - interface ProductVariantMediaProps { media?: ProductMediaFragment[]; placeholderImage?: string; @@ -69,47 +36,42 @@ export const ProductVariantMedia: React.FC< ProductVariantMediaProps > = props => { const intl = useIntl(); - const classes = useStyles(props); const { disabled, media, onImageAdd } = props; return ( - - + + + + {intl.formatMessage(messages.media)} + - } - /> - -
+ + + + {media === undefined || media === null ? ( ) : media.length > 0 ? ( media .sort((prev, next) => (prev.sortOrder > next.sortOrder ? 1 : -1)) .map(mediaObj => { - const parsedMediaOembedData = JSON.parse(mediaObj?.oembedData); - const mediaUrl = - parsedMediaOembedData?.thumbnail_url || mediaObj.url; return ( - {mediaObj.alt} ); }) ) : ( - + {intl.formatMessage(messages.selectSpecificVariant)} - + )} -
-
-
+
+ + ); }; ProductVariantMedia.displayName = "ProductVariantMedia"; diff --git a/src/products/components/ProductVariantName/ProductVariantName.tsx b/src/products/components/ProductVariantName/ProductVariantName.tsx index 1cc4938c762..9d2c3dd9bb2 100644 --- a/src/products/components/ProductVariantName/ProductVariantName.tsx +++ b/src/products/components/ProductVariantName/ProductVariantName.tsx @@ -1,9 +1,9 @@ -import CardTitle from "@dashboard/components/CardTitle"; +import { DashboardCard } from "@dashboard/components/Card"; import { ProductErrorFragment } from "@dashboard/graphql"; import { FormChange } from "@dashboard/hooks/useForm"; import { commonMessages } from "@dashboard/intl"; import { getFormErrors, getProductErrorMessage } from "@dashboard/utils/errors"; -import { Card, CardContent, TextField } from "@material-ui/core"; +import { Input } from "@saleor/macaw-ui/next"; import React from "react"; import { useIntl } from "react-intl"; @@ -24,27 +24,27 @@ const ProductVariantName: React.FC = ({ const formErrors = getFormErrors(["name"], errors); return ( - - + + {intl.formatMessage({ id: "T1f2Yl", defaultMessage: "Variant Name", })} - /> - - + + - - + + ); }; diff --git a/src/products/components/ProductVariantNavigation/ProductVariantNavigation.tsx b/src/products/components/ProductVariantNavigation/ProductVariantNavigation.tsx index edd1dc7a715..3195b902ca5 100644 --- a/src/products/components/ProductVariantNavigation/ProductVariantNavigation.tsx +++ b/src/products/components/ProductVariantNavigation/ProductVariantNavigation.tsx @@ -1,32 +1,30 @@ // @ts-strict-ignore -import { Button } from "@dashboard/components/Button"; -import CardTitle from "@dashboard/components/CardTitle"; -import ResponsiveTable from "@dashboard/components/ResponsiveTable"; +import { DashboardCard } from "@dashboard/components/Card"; +import { Divider } from "@dashboard/components/Divider"; import Skeleton from "@dashboard/components/Skeleton"; -import { - SortableTableBody, - SortableTableRow, -} from "@dashboard/components/SortableTable"; -import TableCellAvatar from "@dashboard/components/TableCellAvatar"; -import TableRowLink from "@dashboard/components/TableRowLink"; import { ProductVariantCreateDataQuery, ProductVariantDetailsQuery, } from "@dashboard/graphql"; +import useNavigator from "@dashboard/hooks/useNavigator"; import { sectionNames } from "@dashboard/intl"; import { productVariantAddUrl, productVariantEditUrl, } from "@dashboard/products/urls"; import { ReorderAction } from "@dashboard/types"; -import { Card, TableCell } from "@material-ui/core"; -import clsx from "clsx"; +import { Box, Button, GripIcon, Text, vars } from "@saleor/macaw-ui/next"; import React from "react"; import { FormattedMessage, useIntl } from "react-intl"; +import { Link } from "react-router-dom"; import { renderCollection } from "../../../misc"; +import { ImagePlaceholder } from "./components/ImagePlaceholder"; +import { + SortableContainer, + SortableElement, +} from "./components/SortableContainer"; import { messages } from "./messages"; -import { useStyles } from "./styles"; interface ProductVariantNavigationProps { current?: string; @@ -46,91 +44,125 @@ const ProductVariantNavigation: React.FC< const { current, defaultVariantId, - fallbackThumbnail, productId, isCreate, variants, onReorder, } = props; - const classes = useStyles(props); + const navigate = useNavigator(); const intl = useIntl(); return ( - - - - - {renderCollection(variants, (variant, variantIndex) => { - const isDefault = variant && variant.id === defaultVariantId; - const isActive = variant && variant.id === current; - const thumbnail = variant?.media?.filter( - mediaObj => mediaObj.type === "IMAGE", - )[0]; + + + {intl.formatMessage(sectionNames.variants)} + + + {variants?.length > 0 && } + {renderCollection(variants, (variant, variantIndex) => { + const isDefault = variant && variant.id === defaultVariantId; + const isActive = variant && variant.id === current; + const thumbnail = variant?.media?.filter( + mediaObj => mediaObj.type === "IMAGE", + )[0]; - return ( - + - - - {variant ? variant.name || variant.sku : } - {isDefault && ( - - {intl.formatMessage(messages.defaultVariant)} - - )} - - - ); - })} - {!isCreate ? ( - - - - - - ) : ( - - - - - - - )} - - - + + {thumbnail?.url ? ( + + ) : ( + + )} + + + {variant ? variant.name || variant.sku : } + + {isDefault && ( + + {intl.formatMessage(messages.defaultVariant)} + + )} + + + + + + ); + })} + {!isCreate ? ( + + ) : ( + + + + + + + + + + )} + + ); }; ProductVariantNavigation.displayName = "ProductVariantNavigation"; diff --git a/src/products/components/ProductVariantNavigation/components/ImagePlaceholder.tsx b/src/products/components/ProductVariantNavigation/components/ImagePlaceholder.tsx new file mode 100644 index 00000000000..d5fd9b784b1 --- /dev/null +++ b/src/products/components/ProductVariantNavigation/components/ImagePlaceholder.tsx @@ -0,0 +1,22 @@ +import { ImageIcon } from "@saleor/macaw-ui"; +import { Box } from "@saleor/macaw-ui/next"; +import React from "react"; + +export const ImagePlaceholder = () => { + return ( + + + + ); +}; diff --git a/src/products/components/ProductVariantNavigation/components/SortableContainer.tsx b/src/products/components/ProductVariantNavigation/components/SortableContainer.tsx new file mode 100644 index 00000000000..7afc7fa8f81 --- /dev/null +++ b/src/products/components/ProductVariantNavigation/components/SortableContainer.tsx @@ -0,0 +1,14 @@ +import { Box, BoxProps } from "@saleor/macaw-ui/next"; +import React from "react"; +import { + SortableContainer as SortableContainerHOC, + SortableElement as SortableElementHOC, +} from "react-sortable-hoc"; + +export const SortableContainer = SortableContainerHOC( + ({ children, ...props }: BoxProps) => {children}, +); + +export const SortableElement = SortableElementHOC( + ({ children, ...props }: BoxProps) => {children}, +); diff --git a/src/products/components/ProductVariantNavigation/styles.ts b/src/products/components/ProductVariantNavigation/styles.ts deleted file mode 100644 index b55b68ebde6..00000000000 --- a/src/products/components/ProductVariantNavigation/styles.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { alpha } from "@material-ui/core/styles"; -import { makeStyles } from "@saleor/macaw-ui"; - -export const useStyles = makeStyles( - theme => ({ - colAvatar: { - width: 64, - }, - colName: { - paddingLeft: 0, - }, - defaultVariant: { - color: alpha(theme.palette.text.secondary, 0.6), - display: "block", - }, - firstVariant: { - width: 104, - }, - link: { - cursor: "pointer", - }, - noHandle: { - "&&&": { - paddingRight: theme.spacing(3), - }, - textAlign: "right", - }, - rowActive: { - borderLeft: `${theme.palette.primary.main} solid 2px`, - }, - rowNew: { - "&:hover": { - backgroundColor: "unset !important", - }, - }, - }), - { name: "ProductVariantNavigation" }, -); diff --git a/src/products/components/ProductVariantPage/ProductVariantPage.tsx b/src/products/components/ProductVariantPage/ProductVariantPage.tsx index 3221fdd1c52..bc546ddec24 100644 --- a/src/products/components/ProductVariantPage/ProductVariantPage.tsx +++ b/src/products/components/ProductVariantPage/ProductVariantPage.tsx @@ -259,6 +259,7 @@ const ProductVariantPage: React.FC = ({ {nonSelectionAttributes.length > 0 && ( @@ -312,7 +313,7 @@ const ProductVariantPage: React.FC = ({ )} = ({ const intl = useIntl(); return ( - + + + ); };