diff --git a/.changeset/lovely-times-repair.md b/.changeset/lovely-times-repair.md new file mode 100644 index 00000000000..dad5c7ba376 --- /dev/null +++ b/.changeset/lovely-times-repair.md @@ -0,0 +1,5 @@ +--- +"saleor-dashboard": patch +--- + +Fixed layout of Granted refund page. Transactions details box will no longer have overlayed text on top of each other and will instead add proper scrollbar on small viewport sizes. This page will now also switch to smaller sidebar sooner than other pages in order to show more details on smaller viewport sizes. diff --git a/src/components/AppLayout/AppLayout.tsx b/src/components/AppLayout/AppLayout.tsx index e6981177c22..38f1b95e6ef 100644 --- a/src/components/AppLayout/AppLayout.tsx +++ b/src/components/AppLayout/AppLayout.tsx @@ -7,6 +7,7 @@ import { DevModePanel } from "../DevModePanel/DevModePanel"; import NavigatorSearch from "../NavigatorSearch"; import { useSavebarRef } from "../Savebar/SavebarRefContext"; import { Sidebar } from "../Sidebar"; +import { SidebarProvider } from "../Sidebar/SidebarContext"; import { useStyles } from "./styles"; interface AppLayoutProps { @@ -20,7 +21,7 @@ const AppLayout = ({ children }: AppLayoutProps) => { const [appState] = useAppState(); return ( - <> + @@ -58,7 +59,7 @@ const AppLayout = ({ children }: AppLayoutProps) => { /> - + ); }; diff --git a/src/components/Sidebar/Sidebar.module.css b/src/components/Sidebar/Sidebar.module.css new file mode 100644 index 00000000000..380a8078f0d --- /dev/null +++ b/src/components/Sidebar/Sidebar.module.css @@ -0,0 +1,21 @@ +.fullSidebarWide { + height: 100%; + display: none; +} + +.drawerWide { + height: 100%; + display: block; +} + +/** This is used when we want to show smaller sidebar sooner than the default 1024px +* in order to show more page content */ +@media (min-width: 1200px) { + .fullSidebarWide { + display: block; + } + + .drawerWide { + display: none; + } +} diff --git a/src/components/Sidebar/Sidebar.test.tsx b/src/components/Sidebar/Sidebar.test.tsx index dc6e9d9432c..009d07eec1c 100644 --- a/src/components/Sidebar/Sidebar.test.tsx +++ b/src/components/Sidebar/Sidebar.test.tsx @@ -9,6 +9,7 @@ import { ReactNode } from "react"; import { MemoryRouter } from "react-router-dom"; import { Sidebar } from "./Sidebar"; +import { SidebarProvider } from "./SidebarContext"; jest.mock("./menu/hooks/useMenuStructure", () => ({ useMenuStructure: jest.fn(() => []), @@ -55,7 +56,9 @@ const Wrapper = ({ children }: { children: ReactNode }) => { {/* @ts-expect-error - legacy types */} - {children} + + {children} + ); diff --git a/src/components/Sidebar/Sidebar.tsx b/src/components/Sidebar/Sidebar.tsx index 875b854551c..6718c554629 100644 --- a/src/components/Sidebar/Sidebar.tsx +++ b/src/components/Sidebar/Sidebar.tsx @@ -1,38 +1,79 @@ import { Box, Drawer, MenuIcon } from "@saleor/macaw-ui-next"; import { SidebarContent } from "./Content"; +import classes from "./Sidebar.module.css"; +import { useSidebarBreakpointContext } from "./SidebarContext"; -export const Sidebar = () => ( - <> - - - - - - - - +export const Sidebar = () => { + const { breakpoint } = useSidebarBreakpointContext(); + + if (breakpoint === "wide") { + return ( + <> +
+ + - - - - - - - -); +
+
+ + + + + + + + + + +
+ + ); + } + + return ( + <> + + + + + + + + + + + + + + + + + ); +}; diff --git a/src/components/Sidebar/SidebarContext.tsx b/src/components/Sidebar/SidebarContext.tsx new file mode 100644 index 00000000000..83ee58339b2 --- /dev/null +++ b/src/components/Sidebar/SidebarContext.tsx @@ -0,0 +1,56 @@ +import { createContext, ReactNode, useContext, useEffect, useState } from "react"; + +type SidebarBreakpoint = "default" | "wide"; + +interface SidebarContextValue { + breakpoint: SidebarBreakpoint; + setBreakpoint: (breakpoint: SidebarBreakpoint) => void; +} + +const SidebarContext = createContext(undefined); + +export const SidebarProvider = ({ children }: { children: ReactNode }) => { + const [breakpoint, setBreakpoint] = useState("default"); + + return ( + + {children} + + ); +}; + +export const useSidebarBreakpointContext = () => { + const context = useContext(SidebarContext); + + if (context === undefined) { + throw new Error("useSidebarBreakpoint must be used within a SidebarProvider"); + } + + return context; +}; + +/** + * Hook to set a custom sidebar breakpoint for a page. + * The breakpoint is automatically reset to "default" when the component unmounts. + * + * @param breakpoint - The breakpoint to use ("default" or "wide") + * + * @example + * ```tsx + * const MyPage = () => { + * useCustomSidebarBreakpoint("wide"); + * return
Page content
; + * }; + * ``` + */ +export const useCustomSidebarBreakpoint = (breakpoint: SidebarBreakpoint) => { + const { setBreakpoint } = useSidebarBreakpointContext(); + + useEffect(() => { + setBreakpoint(breakpoint); + + return () => { + setBreakpoint("default"); + }; + }, [breakpoint, setBreakpoint]); +}; diff --git a/src/orders/components/OrderManualTransactionRefundPage/OrderManualTransactionRefundPage.tsx b/src/orders/components/OrderManualTransactionRefundPage/OrderManualTransactionRefundPage.tsx index 994f027e3c6..320df7010bc 100644 --- a/src/orders/components/OrderManualTransactionRefundPage/OrderManualTransactionRefundPage.tsx +++ b/src/orders/components/OrderManualTransactionRefundPage/OrderManualTransactionRefundPage.tsx @@ -184,7 +184,7 @@ export const OrderManualTransactionRefundPage = ({ - +
diff --git a/src/orders/components/OrderTransactionRefundPage/OrderTransactionRefundPage.tsx b/src/orders/components/OrderTransactionRefundPage/OrderTransactionRefundPage.tsx index 89314ba35a7..86ccb61f8a2 100644 --- a/src/orders/components/OrderTransactionRefundPage/OrderTransactionRefundPage.tsx +++ b/src/orders/components/OrderTransactionRefundPage/OrderTransactionRefundPage.tsx @@ -6,6 +6,7 @@ import Link from "@dashboard/components/Link"; import { Pill } from "@dashboard/components/Pill"; import { hasPermissions } from "@dashboard/components/RequirePermissions"; import { Savebar } from "@dashboard/components/Savebar"; +import { useCustomSidebarBreakpoint } from "@dashboard/components/Sidebar/SidebarContext"; import { OrderDetailsGrantRefundFragment, PermissionEnum, @@ -145,6 +146,9 @@ const OrderTransactionRefundPage = ({ const navigate = useNavigator(); const intl = useIntl(); + // Use wider breakpoint to show minimal sidebar and give more horizontal space for the transaction table + useCustomSidebarBreakpoint("wide"); + const [editedRefundLineIndex, setEditedRefundLineIndex] = useState(null); const datagridErrors: OrderRefundTransactionDatagridError[] = errors @@ -289,8 +293,14 @@ const OrderTransactionRefundPage = ({ - - + + - + Refund reason diff --git a/src/orders/components/OrderTransactionRefundPage/components/OrderTransactionRefundSummary/OrderTransactionSummary.tsx b/src/orders/components/OrderTransactionRefundPage/components/OrderTransactionRefundSummary/OrderTransactionSummary.tsx index f5c3c2c36b0..f12b37a8469 100644 --- a/src/orders/components/OrderTransactionRefundPage/components/OrderTransactionRefundSummary/OrderTransactionSummary.tsx +++ b/src/orders/components/OrderTransactionRefundPage/components/OrderTransactionRefundSummary/OrderTransactionSummary.tsx @@ -20,6 +20,29 @@ interface OrderTransactionSummaryProps extends BoxProps { currency: string | undefined; } +// For usage in grid that exceeds padding for full background line +// Negative spacing offsets the parent container's padding (paddingLeft={3}, padding={4}) +const FullWidthLine = () => { + return ( + + + + ); +}; + export const OrderTransactionSummary = ({ amountError, control, @@ -49,38 +72,36 @@ export const OrderTransactionSummary = ({ - + - + {/* Selected products row - no checkbox */} + - {currency ? ( - - ) : ( - - - - )} - - + + {currency ? ( + + ) : ( + + + + )} + + + + {canRefundShipping ? ( - + @@ -89,6 +110,7 @@ export const OrderTransactionSummary = ({ )} - {shippingCost ? ( - - ) : ( - - - - )} - - - + + {shippingCost ? ( + + ) : ( + + + + )} + + + + + {/* Total row */} + + + {/* Error message */} + {!!amountError && ( + <> + + + {amountError.message} + + + + )} - {!!amountError && ( - - - {amountError.message} - - - )} diff --git a/src/orders/components/OrderTransactionRefundPage/components/OrderTransactionTiles/OrderTransactionTiles.tsx b/src/orders/components/OrderTransactionRefundPage/components/OrderTransactionTiles/OrderTransactionTiles.tsx index c81238e7336..24433a4b1cd 100644 --- a/src/orders/components/OrderTransactionRefundPage/components/OrderTransactionTiles/OrderTransactionTiles.tsx +++ b/src/orders/components/OrderTransactionRefundPage/components/OrderTransactionTiles/OrderTransactionTiles.tsx @@ -27,7 +27,7 @@ export const OrderTransactionTiles = ({ transactions, control }: OrderTransactio if (!transactions) { return ( - + ); } @@ -35,68 +35,111 @@ export const OrderTransactionTiles = ({ transactions, control }: OrderTransactio return ( - + {transactions.map(transaction => { const isDisabled = !transaction.actions.includes(TransactionActionEnum.REFUND); return ( - {isDisabled ? ( - - - - - - - - - - - ) : ( - - )} - - {transaction.events.map((event, eventIndex) => { - const { type, status } = mapTransactionEvent(event); - - return ( - - - + + {isDisabled ? ( + + + + + + + + + + ) : ( + + )} + + {transaction.events.map((event, eventIndex) => { + const { type, status } = mapTransactionEvent(event); + const isLastRow = eventIndex === transaction.events.length - 1; + + return ( + <> + + + - - - {event.pspReference ? ( - - ) : ( - - )} - - - ); - })} + + + + + + + + {event.pspReference ? ( + + ) : ( + + )} + + + + + {!isLastRow && ( + + )} + + ); + })} + ); diff --git a/src/orders/components/OrderTransactionRefundPage/components/OrderTransactionTiles/TileHeader.tsx b/src/orders/components/OrderTransactionRefundPage/components/OrderTransactionTiles/TileHeader.tsx index e3f7b70972c..5ec580d9065 100644 --- a/src/orders/components/OrderTransactionRefundPage/components/OrderTransactionTiles/TileHeader.tsx +++ b/src/orders/components/OrderTransactionRefundPage/components/OrderTransactionTiles/TileHeader.tsx @@ -13,12 +13,13 @@ interface TileHeaderProps { export const TileHeader = ({ transaction, isDisabled = false }: TileHeaderProps) => { return (