Add filters to staff member list

This commit is contained in:
dominik-zeglen 2020-01-07 13:06:11 +01:00
parent eab3d67502
commit 04e9e13c5a
7 changed files with 157 additions and 14 deletions

View file

@ -6,21 +6,26 @@ import { FormattedMessage, useIntl } from "react-intl";
import AppHeader from "@saleor/components/AppHeader"; import AppHeader from "@saleor/components/AppHeader";
import { Container } from "@saleor/components/Container"; import { Container } from "@saleor/components/Container";
import PageHeader from "@saleor/components/PageHeader"; import PageHeader from "@saleor/components/PageHeader";
import SearchBar from "@saleor/components/SearchBar"; import FilterBar from "@saleor/components/FilterBar";
import { sectionNames } from "@saleor/intl"; import { sectionNames } from "@saleor/intl";
import { import {
ListProps, ListProps,
SearchPageProps, FilterPageProps,
TabPageProps, TabPageProps,
SortPage SortPage
} from "@saleor/types"; } from "@saleor/types";
import { StaffListUrlSortField } from "@saleor/staff/urls"; import { StaffListUrlSortField } from "@saleor/staff/urls";
import {
StaffFilterKeys,
createFilterStructure
} from "@saleor/staff/views/StaffList/filter";
import { StaffListFilterOpts } from "@saleor/staff/types";
import { StaffList_staffUsers_edges_node } from "../../types/StaffList"; import { StaffList_staffUsers_edges_node } from "../../types/StaffList";
import StaffList from "../StaffList/StaffList"; import StaffList from "../StaffList/StaffList";
export interface StaffListPageProps export interface StaffListPageProps
extends ListProps, extends ListProps,
SearchPageProps, FilterPageProps<StaffFilterKeys, StaffListFilterOpts>,
SortPage<StaffListUrlSortField>, SortPage<StaffListUrlSortField>,
TabPageProps { TabPageProps {
staffMembers: StaffList_staffUsers_edges_node[]; staffMembers: StaffList_staffUsers_edges_node[];
@ -29,11 +34,14 @@ export interface StaffListPageProps
} }
const StaffListPage: React.FC<StaffListPageProps> = ({ const StaffListPage: React.FC<StaffListPageProps> = ({
currencySymbol,
currentTab, currentTab,
filterOpts,
initialSearch, initialSearch,
onAdd, onAdd,
onAll, onAll,
onBack, onBack,
onFilterChange,
onSearchChange, onSearchChange,
onTabChange, onTabChange,
onTabDelete, onTabDelete,
@ -43,6 +51,8 @@ const StaffListPage: React.FC<StaffListPageProps> = ({
}) => { }) => {
const intl = useIntl(); const intl = useIntl();
const structure = createFilterStructure(intl, filterOpts);
return ( return (
<Container> <Container>
<AppHeader onBack={onBack}> <AppHeader onBack={onBack}>
@ -57,18 +67,21 @@ const StaffListPage: React.FC<StaffListPageProps> = ({
</Button> </Button>
</PageHeader> </PageHeader>
<Card> <Card>
<SearchBar <FilterBar
allTabLabel={intl.formatMessage({ allTabLabel={intl.formatMessage({
defaultMessage: "All Staff Members", defaultMessage: "All Staff Members",
description: "tab name" description: "tab name"
})} })}
currencySymbol={currencySymbol}
currentTab={currentTab} currentTab={currentTab}
filterStructure={structure}
initialSearch={initialSearch} initialSearch={initialSearch}
searchPlaceholder={intl.formatMessage({ searchPlaceholder={intl.formatMessage({
defaultMessage: "Search Staff Member" defaultMessage: "Search Staff Member"
})} })}
tabs={tabs} tabs={tabs}
onAll={onAll} onAll={onAll}
onFilterChange={onFilterChange}
onSearchChange={onSearchChange} onSearchChange={onSearchChange}
onTabChange={onTabChange} onTabChange={onTabChange}
onTabDelete={onTabDelete} onTabDelete={onTabDelete}

6
src/staff/types.ts Normal file
View file

@ -0,0 +1,6 @@
import { FilterOpts } from "@saleor/types";
import { StaffMemberStatus } from "@saleor/types/globalTypes";
export interface StaffListFilterOpts {
status: FilterOpts<StaffMemberStatus>;
}

View file

@ -15,6 +15,7 @@ const staffSection = "/staff/";
export const staffListPath = staffSection; export const staffListPath = staffSection;
export enum StaffListUrlFiltersEnum { export enum StaffListUrlFiltersEnum {
status = "status",
query = "query" query = "query"
} }
export type StaffListUrlFilters = Filters<StaffListUrlFiltersEnum>; export type StaffListUrlFilters = Filters<StaffListUrlFiltersEnum>;

View file

@ -23,6 +23,8 @@ import { ListViews } from "@saleor/types";
import { getSortParams } from "@saleor/utils/sort"; import { getSortParams } from "@saleor/utils/sort";
import createSortHandler from "@saleor/utils/handlers/sortHandler"; import createSortHandler from "@saleor/utils/handlers/sortHandler";
import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers"; import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers";
import { IFilter } from "@saleor/components/Filter";
import { getFilterQueryParams } from "@saleor/utils/filters";
import StaffAddMemberDialog, { import StaffAddMemberDialog, {
FormData as AddStaffMemberForm FormData as AddStaffMemberForm
} from "../../components/StaffAddMemberDialog"; } from "../../components/StaffAddMemberDialog";
@ -33,7 +35,6 @@ import { StaffMemberAdd } from "../../types/StaffMemberAdd";
import { import {
staffListUrl, staffListUrl,
StaffListUrlDialog, StaffListUrlDialog,
StaffListUrlFilters,
StaffListUrlQueryParams, StaffListUrlQueryParams,
staffMemberDetailsUrl staffMemberDetailsUrl
} from "../../urls"; } from "../../urls";
@ -43,7 +44,10 @@ import {
getActiveFilters, getActiveFilters,
getFilterTabs, getFilterTabs,
getFilterVariables, getFilterVariables,
saveFilterTab saveFilterTab,
StaffFilterKeys,
getFilterQueryParam,
getFilterOpts
} from "./filter"; } from "./filter";
import { getSortQueryVariables } from "./sort"; import { getSortQueryVariables } from "./sort";
@ -62,6 +66,7 @@ export const StaffList: React.FC<StaffListProps> = ({ params }) => {
const shop = useShop(); const shop = useShop();
const paginationState = createPaginationState(settings.rowNumber, params); const paginationState = createPaginationState(settings.rowNumber, params);
const currencySymbol = maybe(() => shop.defaultCurrency, "USD");
const queryVariables = React.useMemo( const queryVariables = React.useMemo(
() => ({ () => ({
...paginationState, ...paginationState,
@ -84,15 +89,32 @@ export const StaffList: React.FC<StaffListProps> = ({ params }) => {
: 0 : 0
: parseInt(params.activeTab, 0); : parseInt(params.activeTab, 0);
const changeFilterField = (filter: StaffListUrlFilters) => const changeFilters = (filter: IFilter<StaffFilterKeys>) =>
navigate( navigate(
staffListUrl({ staffListUrl({
...getActiveFilters(params), ...params,
...filter, ...getFilterQueryParams(filter, getFilterQueryParam),
activeTab: undefined activeTab: undefined
}) })
); );
const resetFilters = () =>
navigate(
staffListUrl({
asc: params.asc,
sort: params.sort
})
);
const handleSearchChange = (query: string) =>
navigate(
staffListUrl({
...params,
activeTab: undefined,
query
})
);
const [openModal, closeModal] = createDialogActionHandlers< const [openModal, closeModal] = createDialogActionHandlers<
StaffListUrlDialog, StaffListUrlDialog,
StaffListUrlQueryParams StaffListUrlQueryParams
@ -159,10 +181,13 @@ export const StaffList: React.FC<StaffListProps> = ({ params }) => {
return ( return (
<> <>
<StaffListPage <StaffListPage
currencySymbol={currencySymbol}
currentTab={currentTab} currentTab={currentTab}
filterOpts={getFilterOpts(params)}
initialSearch={params.query || ""} initialSearch={params.query || ""}
onSearchChange={query => changeFilterField({ query })} onSearchChange={handleSearchChange}
onAll={() => navigate(staffListUrl())} onFilterChange={changeFilters}
onAll={resetFilters}
onTabChange={handleTabChange} onTabChange={handleTabChange}
onTabDelete={() => openModal("delete-search")} onTabDelete={() => openModal("delete-search")}
onTabSave={() => openModal("save-search")} onTabSave={() => openModal("save-search")}

View file

@ -1,4 +1,9 @@
import { StaffUserInput } from "@saleor/types/globalTypes"; import { IntlShape } from "react-intl";
import { StaffUserInput, StaffMemberStatus } from "@saleor/types/globalTypes";
import { maybe, findValueInEnum } from "@saleor/misc";
import { IFilter, IFilterElement } from "@saleor/components/Filter";
import { createOptionsField } from "@saleor/utils/filters/fields";
import { import {
createFilterTabUtils, createFilterTabUtils,
createFilterUtils createFilterUtils
@ -8,17 +13,83 @@ import {
StaffListUrlFiltersEnum, StaffListUrlFiltersEnum,
StaffListUrlQueryParams StaffListUrlQueryParams
} from "../../urls"; } from "../../urls";
import { StaffListFilterOpts } from "../../types";
import messages from "./messages";
export const STAFF_FILTERS_KEY = "staffFilters"; export const STAFF_FILTERS_KEY = "staffFilters";
export enum StaffFilterKeys {
status = "status"
}
export function getFilterOpts(
params: StaffListUrlFilters
): StaffListFilterOpts {
return {
status: {
active: maybe(() => params.status !== undefined, false),
value: maybe(() => findValueInEnum(params.status, StaffMemberStatus))
}
};
}
export function createFilterStructure(
intl: IntlShape,
opts: StaffListFilterOpts
): IFilter<StaffFilterKeys> {
return [
{
...createOptionsField(
StaffFilterKeys.status,
intl.formatMessage(messages.status),
[opts.status.value],
false,
[
{
label: intl.formatMessage(messages.active),
value: StaffMemberStatus.ACTIVE
},
{
label: intl.formatMessage(messages.deactivated),
value: StaffMemberStatus.DEACTIVATED
}
]
),
active: opts.status.active
}
];
}
export function getFilterVariables( export function getFilterVariables(
params: StaffListUrlFilters params: StaffListUrlFilters
): StaffUserInput { ): StaffUserInput {
return { return {
search: params.query search: params.query,
status: params.status
? findValueInEnum(params.status, StaffMemberStatus)
: null
}; };
} }
export function getFilterQueryParam(
filter: IFilterElement<StaffFilterKeys>
): StaffListUrlFilters {
const { active, name, value } = filter;
switch (name) {
case StaffFilterKeys.status:
if (!active) {
return {
status: undefined
};
}
return {
status: value[0]
};
}
}
export const { export const {
deleteFilterTab, deleteFilterTab,
getFilterTabs, getFilterTabs,

View file

@ -0,0 +1,18 @@
import { defineMessages } from "react-intl";
const messages = defineMessages({
active: {
defaultMessage: "Active",
description: "staff member's account"
},
deactivated: {
defaultMessage: "Deactivated",
description: "staff member's account"
},
status: {
defaultMessage: "Status",
description: "staff member's account"
}
});
export default messages;

View file

@ -2,11 +2,13 @@ import { storiesOf } from "@storybook/react";
import React from "react"; import React from "react";
import { StaffListUrlSortField } from "@saleor/staff/urls"; import { StaffListUrlSortField } from "@saleor/staff/urls";
import { StaffMemberStatus } from "@saleor/types/globalTypes";
import { import {
pageListProps, pageListProps,
searchPageProps, searchPageProps,
tabPageProps, tabPageProps,
sortPageProps sortPageProps,
filterPageProps
} from "../../../fixtures"; } from "../../../fixtures";
import StaffListPage, { import StaffListPage, {
StaffListPageProps StaffListPageProps
@ -19,6 +21,13 @@ const props: StaffListPageProps = {
...searchPageProps, ...searchPageProps,
...sortPageProps, ...sortPageProps,
...tabPageProps, ...tabPageProps,
...filterPageProps,
filterOpts: {
status: {
active: false,
value: StaffMemberStatus.ACTIVE
}
},
onAdd: undefined, onAdd: undefined,
onBack: () => undefined, onBack: () => undefined,
sort: { sort: {