Skip to content

Commit

Permalink
New home page sidebar and Title (#5268)
Browse files Browse the repository at this point in the history
* Add feature flag for new home page

* New home page with layout

* Conditionally render new and old home page

* Add changeset

* Init new sidebar

* Base analytics cards

* Base activities cards

* Refactor and move fetching logic to hooks near components

* Single queries file

* Add home title

* Move common props to context

* Add permission checks

* Add change

* Rollback type

* Improve query data

* Fix typo

* Fix translations

* Fix types

* Fix types v2

* Restruct dir structure to align with current setup

* Move context inside

* Update queries

---------

Co-authored-by: M.Graczyk <[email protected]>
  • Loading branch information
poulch and michalina-graczyk committed Nov 29, 2024
1 parent f9130c4 commit 9cd4da2
Show file tree
Hide file tree
Showing 26 changed files with 720 additions and 24 deletions.
5 changes: 5 additions & 0 deletions .changeset/pretty-fans-push.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"saleor-dashboard": patch
---

You can now see new sidebar with analytics and activities
7 changes: 7 additions & 0 deletions locale/defaultMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,9 @@
"context": "order returned success message",
"string": "Successfully returned products!"
},
"0+zatS": {
"string": "Hello {userName}, welcome to your Store Dashboard"
},
"01+5kQ": {
"string": "Mark as paid"
},
Expand Down Expand Up @@ -9282,6 +9285,10 @@
"x0n6YG": {
"string": "This refund is currently being processed and cannot be edited"
},
"x0wum5": {
"context": "home sidebar card title",
"string": "Your store info"
},
"x2mg39": {
"context": "Transaction event description",
"string": "Used in order"
Expand Down
4 changes: 2 additions & 2 deletions src/components/Layouts/Detail/Content.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Box } from "@saleor/macaw-ui-next";
import { Box, BoxProps } from "@saleor/macaw-ui-next";
import React from "react";

interface DetailPageLayoutContentProps {
interface DetailPageLayoutContentProps extends BoxProps {
[key: `data-${string}`]: string;
children: React.ReactNode;
}
Expand Down
10 changes: 7 additions & 3 deletions src/components/Layouts/Detail/RightSidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { Box } from "@saleor/macaw-ui-next";
import { Box, BoxProps } from "@saleor/macaw-ui-next";
import React from "react";

interface DetailPageLayoutRightSidebarProps {
interface DetailPageLayoutRightSidebarProps extends BoxProps {
children: React.ReactNode;
}

export const RightSidebar: React.FC<DetailPageLayoutRightSidebarProps> = ({ children }) => (
export const RightSidebar: React.FC<DetailPageLayoutRightSidebarProps> = ({
children,
...props
}) => (
<Box
borderLeftStyle="solid"
borderColor="default1"
Expand All @@ -16,6 +19,7 @@ export const RightSidebar: React.FC<DetailPageLayoutRightSidebarProps> = ({ chil
gridColumn={"8"}
gridRow={{ mobile: "6", tablet: "full", desktop: "full" }}
paddingBottom={6}
{...props}
>
{children}
</Box>
Expand Down
123 changes: 123 additions & 0 deletions src/graphql/hooks.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10147,6 +10147,129 @@ export function useMenuDetailsLazyQuery(baseOptions?: ApolloReactHooks.LazyQuery
export type MenuDetailsQueryHookResult = ReturnType<typeof useMenuDetailsQuery>;
export type MenuDetailsLazyQueryHookResult = ReturnType<typeof useMenuDetailsLazyQuery>;
export type MenuDetailsQueryResult = Apollo.QueryResult<Types.MenuDetailsQuery, Types.MenuDetailsQueryVariables>;
export const WelcomePageActivitiesDocument = gql`
query WelcomePageActivities($hasPermissionToManageOrders: Boolean!) {
activities: homepageEvents(last: 10) @include(if: $hasPermissionToManageOrders) {
edges {
node {
date
email
message
orderNumber
type
user {
email
}
}
}
}
}
`;

/**
* __useWelcomePageActivitiesQuery__
*
* To run a query within a React component, call `useWelcomePageActivitiesQuery` and pass it any options that fit your needs.
* When your component renders, `useWelcomePageActivitiesQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useWelcomePageActivitiesQuery({
* variables: {
* hasPermissionToManageOrders: // value for 'hasPermissionToManageOrders'
* },
* });
*/
export function useWelcomePageActivitiesQuery(baseOptions: ApolloReactHooks.QueryHookOptions<Types.WelcomePageActivitiesQuery, Types.WelcomePageActivitiesQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return ApolloReactHooks.useQuery<Types.WelcomePageActivitiesQuery, Types.WelcomePageActivitiesQueryVariables>(WelcomePageActivitiesDocument, options);
}
export function useWelcomePageActivitiesLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions<Types.WelcomePageActivitiesQuery, Types.WelcomePageActivitiesQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return ApolloReactHooks.useLazyQuery<Types.WelcomePageActivitiesQuery, Types.WelcomePageActivitiesQueryVariables>(WelcomePageActivitiesDocument, options);
}
export type WelcomePageActivitiesQueryHookResult = ReturnType<typeof useWelcomePageActivitiesQuery>;
export type WelcomePageActivitiesLazyQueryHookResult = ReturnType<typeof useWelcomePageActivitiesLazyQuery>;
export type WelcomePageActivitiesQueryResult = Apollo.QueryResult<Types.WelcomePageActivitiesQuery, Types.WelcomePageActivitiesQueryVariables>;
export const WelcomePageAnalyticsDocument = gql`
query WelcomePageAnalytics($channel: String!, $hasPermissionToManageOrders: Boolean!) {
salesToday: ordersTotal(period: TODAY, channel: $channel) @include(if: $hasPermissionToManageOrders) {
gross {
amount
currency
}
}
}
`;

/**
* __useWelcomePageAnalyticsQuery__
*
* To run a query within a React component, call `useWelcomePageAnalyticsQuery` and pass it any options that fit your needs.
* When your component renders, `useWelcomePageAnalyticsQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useWelcomePageAnalyticsQuery({
* variables: {
* channel: // value for 'channel'
* hasPermissionToManageOrders: // value for 'hasPermissionToManageOrders'
* },
* });
*/
export function useWelcomePageAnalyticsQuery(baseOptions: ApolloReactHooks.QueryHookOptions<Types.WelcomePageAnalyticsQuery, Types.WelcomePageAnalyticsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return ApolloReactHooks.useQuery<Types.WelcomePageAnalyticsQuery, Types.WelcomePageAnalyticsQueryVariables>(WelcomePageAnalyticsDocument, options);
}
export function useWelcomePageAnalyticsLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions<Types.WelcomePageAnalyticsQuery, Types.WelcomePageAnalyticsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return ApolloReactHooks.useLazyQuery<Types.WelcomePageAnalyticsQuery, Types.WelcomePageAnalyticsQueryVariables>(WelcomePageAnalyticsDocument, options);
}
export type WelcomePageAnalyticsQueryHookResult = ReturnType<typeof useWelcomePageAnalyticsQuery>;
export type WelcomePageAnalyticsLazyQueryHookResult = ReturnType<typeof useWelcomePageAnalyticsLazyQuery>;
export type WelcomePageAnalyticsQueryResult = Apollo.QueryResult<Types.WelcomePageAnalyticsQuery, Types.WelcomePageAnalyticsQueryVariables>;
export const WelcomePageNotificationsDocument = gql`
query welcomePageNotifications($channel: String!) {
productsOutOfStock: products(
filter: {stockAvailability: OUT_OF_STOCK}
channel: $channel
) {
totalCount
}
}
`;

/**
* __useWelcomePageNotificationsQuery__
*
* To run a query within a React component, call `useWelcomePageNotificationsQuery` and pass it any options that fit your needs.
* When your component renders, `useWelcomePageNotificationsQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useWelcomePageNotificationsQuery({
* variables: {
* channel: // value for 'channel'
* },
* });
*/
export function useWelcomePageNotificationsQuery(baseOptions: ApolloReactHooks.QueryHookOptions<Types.WelcomePageNotificationsQuery, Types.WelcomePageNotificationsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return ApolloReactHooks.useQuery<Types.WelcomePageNotificationsQuery, Types.WelcomePageNotificationsQueryVariables>(WelcomePageNotificationsDocument, options);
}
export function useWelcomePageNotificationsLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions<Types.WelcomePageNotificationsQuery, Types.WelcomePageNotificationsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return ApolloReactHooks.useLazyQuery<Types.WelcomePageNotificationsQuery, Types.WelcomePageNotificationsQueryVariables>(WelcomePageNotificationsDocument, options);
}
export type WelcomePageNotificationsQueryHookResult = ReturnType<typeof useWelcomePageNotificationsQuery>;
export type WelcomePageNotificationsLazyQueryHookResult = ReturnType<typeof useWelcomePageNotificationsLazyQuery>;
export type WelcomePageNotificationsQueryResult = Apollo.QueryResult<Types.WelcomePageNotificationsQuery, Types.WelcomePageNotificationsQueryVariables>;
export const OrderCancelDocument = gql`
mutation OrderCancel($id: ID!) {
orderCancel(id: $id) {
Expand Down
22 changes: 22 additions & 0 deletions src/graphql/types.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10745,6 +10745,28 @@ export type MenuDetailsQueryVariables = Exact<{

export type MenuDetailsQuery = { __typename: 'Query', menu: { __typename: 'Menu', id: string, name: string, items: Array<{ __typename: 'MenuItem', id: string, level: number, name: string, url: string | null, children: Array<{ __typename: 'MenuItem', id: string, level: number, name: string, url: string | null, children: Array<{ __typename: 'MenuItem', id: string, level: number, name: string, url: string | null, children: Array<{ __typename: 'MenuItem', id: string, level: number, name: string, url: string | null, children: Array<{ __typename: 'MenuItem', id: string, level: number, name: string, url: string | null, children: Array<{ __typename: 'MenuItem', id: string, level: number, name: string, url: string | null, children: Array<{ __typename: 'MenuItem', id: string, level: number, name: string, url: string | null, category: { __typename: 'Category', id: string, name: string } | null, collection: { __typename: 'Collection', id: string, name: string } | null, page: { __typename: 'Page', id: string, title: string } | null }> | null, category: { __typename: 'Category', id: string, name: string } | null, collection: { __typename: 'Collection', id: string, name: string } | null, page: { __typename: 'Page', id: string, title: string } | null }> | null, category: { __typename: 'Category', id: string, name: string } | null, collection: { __typename: 'Collection', id: string, name: string } | null, page: { __typename: 'Page', id: string, title: string } | null }> | null, category: { __typename: 'Category', id: string, name: string } | null, collection: { __typename: 'Collection', id: string, name: string } | null, page: { __typename: 'Page', id: string, title: string } | null }> | null, category: { __typename: 'Category', id: string, name: string } | null, collection: { __typename: 'Collection', id: string, name: string } | null, page: { __typename: 'Page', id: string, title: string } | null }> | null, category: { __typename: 'Category', id: string, name: string } | null, collection: { __typename: 'Collection', id: string, name: string } | null, page: { __typename: 'Page', id: string, title: string } | null }> | null, category: { __typename: 'Category', id: string, name: string } | null, collection: { __typename: 'Collection', id: string, name: string } | null, page: { __typename: 'Page', id: string, title: string } | null }> | null } | null };

export type WelcomePageActivitiesQueryVariables = Exact<{
hasPermissionToManageOrders: Scalars['Boolean'];
}>;


export type WelcomePageActivitiesQuery = { __typename: 'Query', activities: { __typename: 'OrderEventCountableConnection', edges: Array<{ __typename: 'OrderEventCountableEdge', node: { __typename: 'OrderEvent', date: any | null, email: string | null, message: string | null, orderNumber: string | null, type: OrderEventsEnum | null, user: { __typename: 'User', email: string } | null } }> } | null };

export type WelcomePageAnalyticsQueryVariables = Exact<{
channel: Scalars['String'];
hasPermissionToManageOrders: Scalars['Boolean'];
}>;


export type WelcomePageAnalyticsQuery = { __typename: 'Query', salesToday: { __typename: 'TaxedMoney', gross: { __typename: 'Money', amount: number, currency: string } } | null };

export type WelcomePageNotificationsQueryVariables = Exact<{
channel: Scalars['String'];
}>;


export type WelcomePageNotificationsQuery = { __typename: 'Query', productsOutOfStock: { __typename: 'ProductCountableConnection', totalCount: number | null } | null };

export type OrderCancelMutationVariables = Exact<{
id: Scalars['ID'];
}>;
Expand Down
28 changes: 23 additions & 5 deletions src/newHome/HomePage.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,38 @@
import { useUser } from "@dashboard/auth";
import useAppChannel from "@dashboard/components/AppLayout/AppChannelContext";
import { DetailPageLayout } from "@dashboard/components/Layouts";
import { hasPermissions } from "@dashboard/components/RequirePermissions";
import { PermissionEnum } from "@dashboard/graphql";
import { Box } from "@saleor/macaw-ui-next";
import React from "react";

import HomeOnboarding from "./homeOnboarding/HomeOnboarding";
import { HomeSidebar } from "./HomeSidebar";
import { HomeTitle } from "./HomeTitle";

export const HomePage = () => {
const { channel, setChannel } = useAppChannel(false);
const { user } = useUser();
const channels = user?.accessibleChannels ?? [];
const userPermissions = user?.userPermissions || [];
const hasPermissionToManageOrders = hasPermissions(userPermissions, [
PermissionEnum.MANAGE_ORDERS,
]);

return (
<DetailPageLayout withSavebar={false}>
<Box gridColumn="8" gridRowStart="1" />
<DetailPageLayout.Content>
<h1>Hello John, welcome to your Store Dashboard</h1>

<DetailPageLayout.Content marginTop={6} paddingLeft={8}>
<HomeTitle />
<HomeOnboarding />
</DetailPageLayout.Content>
<DetailPageLayout.RightSidebar>
<h1>Right Sidebar</h1>
<DetailPageLayout.RightSidebar borderLeftStyle="none">
<HomeSidebar
channel={channel}
setChannel={setChannel}
channels={channels}
hasPermissionToManageOrders={hasPermissionToManageOrders}
/>
</DetailPageLayout.RightSidebar>
</DetailPageLayout>
);
Expand Down
62 changes: 62 additions & 0 deletions src/newHome/HomeSidebar/HomeSidebar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import AppChannelSelect from "@dashboard/components/AppLayout/AppChannelSelect";
import { topBarHeight } from "@dashboard/components/AppLayout/consts";
import { DashboardCard } from "@dashboard/components/Card";
import RequirePermissions from "@dashboard/components/RequirePermissions";
import { ChannelFragment, PermissionEnum } from "@dashboard/graphql";
import { Box, Text } from "@saleor/macaw-ui-next";
import React from "react";
import { FormattedMessage } from "react-intl";

import { HomeActivities } from "./components/HomeActivities";
import { HomeSalesAnalytics } from "./components/HomeSalesAnalytics";
import { HomeStocksAnalytics } from "./components/HomeStocksAnalytics";
import { HomeSidebarContextProvider } from "./context/HomeSidebarContextProvider";

interface HomeSidebarProps {
channel: ChannelFragment | undefined;
setChannel: (channelId: string) => void;
channels: ChannelFragment[];
hasPermissionToManageOrders: boolean;
}

export const HomeSidebar = (props: HomeSidebarProps) => {
return (
<HomeSidebarContextProvider {...props}>
<DashboardCard
borderRadius={3}
borderWidth={1}
borderStyle="solid"
borderColor="default1"
__marginTop={topBarHeight}
marginRight={5}
>
<DashboardCard.Header>
<DashboardCard.Title>
<Text size={8}>
<FormattedMessage
defaultMessage="Your store info"
id="x0wum5"
description="home sidebar card title"
/>
</Text>
</DashboardCard.Title>

<AppChannelSelect
channels={props.channels}
selectedChannelId={props.channel?.id ?? ""}
onChannelSelect={props.setChannel}
/>
</DashboardCard.Header>
<DashboardCard.Content>
<RequirePermissions requiredPermissions={[PermissionEnum.MANAGE_ORDERS]}>
<Box display="grid" gap={5} marginBottom={7}>
<HomeSalesAnalytics />
<HomeStocksAnalytics />
</Box>
</RequirePermissions>
<HomeActivities />
</DashboardCard.Content>
</DashboardCard>
</HomeSidebarContextProvider>
);
};
Loading

0 comments on commit 9cd4da2

Please sign in to comment.