Add search to staff list
This commit is contained in:
parent
796d1fc0e0
commit
3974b23b15
9 changed files with 301 additions and 126 deletions
|
@ -1,4 +1,3 @@
|
||||||
import Card from "@material-ui/core/Card";
|
|
||||||
import {
|
import {
|
||||||
createStyles,
|
createStyles,
|
||||||
Theme,
|
Theme,
|
||||||
|
@ -84,7 +83,6 @@ const StaffList = withStyles(styles, { name: "StaffList" })(
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card>
|
|
||||||
<Table>
|
<Table>
|
||||||
<TableHead>
|
<TableHead>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
|
@ -125,9 +123,7 @@ const StaffList = withStyles(styles, { name: "StaffList" })(
|
||||||
[classes.tableRow]: !!staffMember
|
[classes.tableRow]: !!staffMember
|
||||||
})}
|
})}
|
||||||
hover={!!staffMember}
|
hover={!!staffMember}
|
||||||
onClick={
|
onClick={!!staffMember ? onRowClick(staffMember.id) : undefined}
|
||||||
!!staffMember ? onRowClick(staffMember.id) : undefined
|
|
||||||
}
|
|
||||||
key={staffMember ? staffMember.id : "skeleton"}
|
key={staffMember ? staffMember.id : "skeleton"}
|
||||||
>
|
>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
|
@ -139,9 +135,7 @@ const StaffList = withStyles(styles, { name: "StaffList" })(
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div className={classes.avatarDefault}>
|
<div className={classes.avatarDefault}>
|
||||||
<Typography>
|
<Typography>{getUserInitials(staffMember)}</Typography>
|
||||||
{getUserInitials(staffMember)}
|
|
||||||
</Typography>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -185,7 +179,6 @@ const StaffList = withStyles(styles, { name: "StaffList" })(
|
||||||
)}
|
)}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
</Card>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,26 +1,37 @@
|
||||||
import Button from "@material-ui/core/Button";
|
import Button from "@material-ui/core/Button";
|
||||||
|
import Card from "@material-ui/core/Card";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
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 { sectionNames } from "@saleor/intl";
|
import { sectionNames } from "@saleor/intl";
|
||||||
import { ListProps } from "@saleor/types";
|
import { ListProps, SearchPageProps, TabPageProps } from "@saleor/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 extends ListProps {
|
export interface StaffListPageProps
|
||||||
|
extends ListProps,
|
||||||
|
SearchPageProps,
|
||||||
|
TabPageProps {
|
||||||
staffMembers: StaffList_staffUsers_edges_node[];
|
staffMembers: StaffList_staffUsers_edges_node[];
|
||||||
onAdd: () => void;
|
onAdd: () => void;
|
||||||
onBack: () => void;
|
onBack: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const StaffListPage: React.StatelessComponent<StaffListPageProps> = ({
|
const StaffListPage: React.StatelessComponent<StaffListPageProps> = ({
|
||||||
disabled,
|
currentTab,
|
||||||
|
initialSearch,
|
||||||
onAdd,
|
onAdd,
|
||||||
|
onAll,
|
||||||
onBack,
|
onBack,
|
||||||
|
onSearchChange,
|
||||||
|
onTabChange,
|
||||||
|
onTabDelete,
|
||||||
|
onTabSave,
|
||||||
|
tabs,
|
||||||
...listProps
|
...listProps
|
||||||
}) => {
|
}) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
@ -31,19 +42,33 @@ const StaffListPage: React.StatelessComponent<StaffListPageProps> = ({
|
||||||
{intl.formatMessage(sectionNames.configuration)}
|
{intl.formatMessage(sectionNames.configuration)}
|
||||||
</AppHeader>
|
</AppHeader>
|
||||||
<PageHeader title={intl.formatMessage(sectionNames.staff)}>
|
<PageHeader title={intl.formatMessage(sectionNames.staff)}>
|
||||||
<Button
|
<Button color="primary" variant="contained" onClick={onAdd}>
|
||||||
color="primary"
|
|
||||||
disabled={disabled}
|
|
||||||
variant="contained"
|
|
||||||
onClick={onAdd}
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
defaultMessage="Invite staff member"
|
defaultMessage="Invite staff member"
|
||||||
description="button"
|
description="button"
|
||||||
/>
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
<StaffList disabled={disabled} {...listProps} />
|
<Card>
|
||||||
|
<SearchBar
|
||||||
|
allTabLabel={intl.formatMessage({
|
||||||
|
defaultMessage: "All Staff Members",
|
||||||
|
description: "tab name"
|
||||||
|
})}
|
||||||
|
currentTab={currentTab}
|
||||||
|
initialSearch={initialSearch}
|
||||||
|
searchPlaceholder={intl.formatMessage({
|
||||||
|
defaultMessage: "Search Staff Member"
|
||||||
|
})}
|
||||||
|
tabs={tabs}
|
||||||
|
onAll={onAll}
|
||||||
|
onSearchChange={onSearchChange}
|
||||||
|
onTabChange={onTabChange}
|
||||||
|
onTabDelete={onTabDelete}
|
||||||
|
onTabSave={onTabSave}
|
||||||
|
/>
|
||||||
|
<StaffList {...listProps} />
|
||||||
|
</Card>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -30,8 +30,20 @@ export const staffMemberDetailsFragment = gql`
|
||||||
`;
|
`;
|
||||||
const staffList = gql`
|
const staffList = gql`
|
||||||
${staffMemberFragment}
|
${staffMemberFragment}
|
||||||
query StaffList($first: Int, $after: String, $last: Int, $before: String) {
|
query StaffList(
|
||||||
staffUsers(before: $before, after: $after, first: $first, last: $last) {
|
$first: Int
|
||||||
|
$after: String
|
||||||
|
$last: Int
|
||||||
|
$before: String
|
||||||
|
$filter: StaffUserInput
|
||||||
|
) {
|
||||||
|
staffUsers(
|
||||||
|
before: $before
|
||||||
|
after: $after
|
||||||
|
first: $first
|
||||||
|
last: $last
|
||||||
|
filter: $filter
|
||||||
|
) {
|
||||||
edges {
|
edges {
|
||||||
cursor
|
cursor
|
||||||
node {
|
node {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
// This file was automatically generated and should not be edited.
|
// This file was automatically generated and should not be edited.
|
||||||
|
|
||||||
import { PermissionEnum } from "./../../types/globalTypes";
|
import { StaffUserInput, PermissionEnum } from "./../../types/globalTypes";
|
||||||
|
|
||||||
// ====================================================
|
// ====================================================
|
||||||
// GraphQL query operation: StaffList
|
// GraphQL query operation: StaffList
|
||||||
|
@ -64,4 +64,5 @@ export interface StaffListVariables {
|
||||||
after?: string | null;
|
after?: string | null;
|
||||||
last?: number | null;
|
last?: number | null;
|
||||||
before?: string | null;
|
before?: string | null;
|
||||||
|
filter?: StaffUserInput | null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,28 @@
|
||||||
import { stringify as stringifyQs } from "qs";
|
import { stringify as stringifyQs } from "qs";
|
||||||
import urlJoin from "url-join";
|
import urlJoin from "url-join";
|
||||||
|
|
||||||
import { BulkAction, Dialog, Pagination } from "../types";
|
import {
|
||||||
|
ActiveTab,
|
||||||
|
BulkAction,
|
||||||
|
Dialog,
|
||||||
|
Filters,
|
||||||
|
Pagination,
|
||||||
|
TabActionDialog
|
||||||
|
} from "../types";
|
||||||
|
|
||||||
const staffSection = "/staff/";
|
const staffSection = "/staff/";
|
||||||
|
|
||||||
export const staffListPath = staffSection;
|
export const staffListPath = staffSection;
|
||||||
export type StaffListUrlDialog = "add" | "remove";
|
export enum StaffListUrlFiltersEnum {
|
||||||
export type StaffListUrlQueryParams = BulkAction &
|
query = "query"
|
||||||
|
}
|
||||||
|
export type StaffListUrlFilters = Filters<StaffListUrlFiltersEnum>;
|
||||||
|
export type StaffListUrlDialog = "add" | "remove" | TabActionDialog;
|
||||||
|
export type StaffListUrlQueryParams = ActiveTab &
|
||||||
|
BulkAction &
|
||||||
Dialog<StaffListUrlDialog> &
|
Dialog<StaffListUrlDialog> &
|
||||||
Pagination;
|
Pagination &
|
||||||
|
StaffListUrlFilters;
|
||||||
export const staffListUrl = (params?: StaffListUrlQueryParams) =>
|
export const staffListUrl = (params?: StaffListUrlQueryParams) =>
|
||||||
staffListPath + "?" + stringifyQs(params);
|
staffListPath + "?" + stringifyQs(params);
|
||||||
|
|
||||||
|
|
|
@ -8,22 +8,36 @@ import usePaginator, {
|
||||||
} from "@saleor/hooks/usePaginator";
|
} from "@saleor/hooks/usePaginator";
|
||||||
import { useIntl } from "react-intl";
|
import { useIntl } from "react-intl";
|
||||||
|
|
||||||
|
import DeleteFilterTabDialog from "@saleor/components/DeleteFilterTabDialog";
|
||||||
|
import SaveFilterTabDialog, {
|
||||||
|
SaveFilterTabDialogFormData
|
||||||
|
} from "@saleor/components/SaveFilterTabDialog";
|
||||||
import { configurationMenuUrl } from "@saleor/configuration";
|
import { configurationMenuUrl } from "@saleor/configuration";
|
||||||
import { commonMessages } from "@saleor/intl";
|
import { commonMessages } from "@saleor/intl";
|
||||||
import { getMutationState, maybe } from "@saleor/misc";
|
import { getMutationState, maybe } from "@saleor/misc";
|
||||||
import { ListViews } from "@saleor/types";
|
import { ListViews } from "@saleor/types";
|
||||||
import StaffAddMemberDialog, {
|
import StaffAddMemberDialog, {
|
||||||
FormData as AddStaffMemberForm
|
FormData as AddStaffMemberForm
|
||||||
} from "../components/StaffAddMemberDialog";
|
} from "../../components/StaffAddMemberDialog";
|
||||||
import StaffListPage from "../components/StaffListPage";
|
import StaffListPage from "../../components/StaffListPage";
|
||||||
import { TypedStaffMemberAddMutation } from "../mutations";
|
import { TypedStaffMemberAddMutation } from "../../mutations";
|
||||||
import { TypedStaffListQuery } from "../queries";
|
import { TypedStaffListQuery } from "../../queries";
|
||||||
import { StaffMemberAdd } from "../types/StaffMemberAdd";
|
import { StaffMemberAdd } from "../../types/StaffMemberAdd";
|
||||||
import {
|
import {
|
||||||
staffListUrl,
|
staffListUrl,
|
||||||
|
StaffListUrlDialog,
|
||||||
|
StaffListUrlFilters,
|
||||||
StaffListUrlQueryParams,
|
StaffListUrlQueryParams,
|
||||||
staffMemberDetailsUrl
|
staffMemberDetailsUrl
|
||||||
} from "../urls";
|
} from "../../urls";
|
||||||
|
import {
|
||||||
|
areFiltersApplied,
|
||||||
|
deleteFilterTab,
|
||||||
|
getActiveFilters,
|
||||||
|
getFilterTabs,
|
||||||
|
getFilterVariables,
|
||||||
|
saveFilterTab
|
||||||
|
} from "./filter";
|
||||||
|
|
||||||
interface StaffListProps {
|
interface StaffListProps {
|
||||||
params: StaffListUrlQueryParams;
|
params: StaffListUrlQueryParams;
|
||||||
|
@ -40,19 +54,72 @@ export const StaffList: React.StatelessComponent<StaffListProps> = ({
|
||||||
);
|
);
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const tabs = getFilterTabs();
|
||||||
|
|
||||||
|
const currentTab =
|
||||||
|
params.activeTab === undefined
|
||||||
|
? areFiltersApplied(params)
|
||||||
|
? tabs.length + 1
|
||||||
|
: 0
|
||||||
|
: parseInt(params.activeTab, 0);
|
||||||
|
|
||||||
|
const changeFilterField = (filter: StaffListUrlFilters) =>
|
||||||
|
navigate(
|
||||||
|
staffListUrl({
|
||||||
|
...getActiveFilters(params),
|
||||||
|
...filter,
|
||||||
|
activeTab: undefined
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
const closeModal = () =>
|
const closeModal = () =>
|
||||||
navigate(
|
navigate(
|
||||||
staffListUrl({
|
staffListUrl({
|
||||||
...params,
|
...params,
|
||||||
action: undefined,
|
action: undefined,
|
||||||
ids: undefined
|
ids: undefined
|
||||||
}),
|
})
|
||||||
true
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const openModal = (action: StaffListUrlDialog, ids?: string[]) =>
|
||||||
|
navigate(
|
||||||
|
staffListUrl({
|
||||||
|
...params,
|
||||||
|
action,
|
||||||
|
ids
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleTabChange = (tab: number) => {
|
||||||
|
navigate(
|
||||||
|
staffListUrl({
|
||||||
|
activeTab: tab.toString(),
|
||||||
|
...getFilterTabs()[tab - 1].data
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTabDelete = () => {
|
||||||
|
deleteFilterTab(currentTab);
|
||||||
|
navigate(staffListUrl());
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTabSave = (data: SaveFilterTabDialogFormData) => {
|
||||||
|
saveFilterTab(data.name, getActiveFilters(params));
|
||||||
|
handleTabChange(tabs.length + 1);
|
||||||
|
};
|
||||||
|
|
||||||
const paginationState = createPaginationState(settings.rowNumber, params);
|
const paginationState = createPaginationState(settings.rowNumber, params);
|
||||||
|
const queryVariables = React.useMemo(
|
||||||
|
() => ({
|
||||||
|
...paginationState,
|
||||||
|
filter: getFilterVariables(params)
|
||||||
|
}),
|
||||||
|
[params]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TypedStaffListQuery displayLoader variables={paginationState}>
|
<TypedStaffListQuery displayLoader variables={queryVariables}>
|
||||||
{({ data, loading }) => {
|
{({ data, loading }) => {
|
||||||
const handleStaffMemberAddSuccess = (data: StaffMemberAdd) => {
|
const handleStaffMemberAddSuccess = (data: StaffMemberAdd) => {
|
||||||
if (data.staffCreate.errors.length === 0) {
|
if (data.staffCreate.errors.length === 0) {
|
||||||
|
@ -97,6 +164,14 @@ export const StaffList: React.StatelessComponent<StaffListProps> = ({
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<StaffListPage
|
<StaffListPage
|
||||||
|
currentTab={currentTab}
|
||||||
|
initialSearch={params.query || ""}
|
||||||
|
onSearchChange={query => changeFilterField({ query })}
|
||||||
|
onAll={() => navigate(staffListUrl())}
|
||||||
|
onTabChange={handleTabChange}
|
||||||
|
onTabDelete={() => openModal("delete-search")}
|
||||||
|
onTabSave={() => openModal("save-search")}
|
||||||
|
tabs={tabs.map(tab => tab.name)}
|
||||||
disabled={loading || addStaffMemberData.loading}
|
disabled={loading || addStaffMemberData.loading}
|
||||||
settings={settings}
|
settings={settings}
|
||||||
pageInfo={pageInfo}
|
pageInfo={pageInfo}
|
||||||
|
@ -126,6 +201,19 @@ export const StaffList: React.StatelessComponent<StaffListProps> = ({
|
||||||
onClose={closeModal}
|
onClose={closeModal}
|
||||||
onConfirm={handleStaffMemberAdd}
|
onConfirm={handleStaffMemberAdd}
|
||||||
/>
|
/>
|
||||||
|
<SaveFilterTabDialog
|
||||||
|
open={params.action === "save-search"}
|
||||||
|
confirmButtonState="default"
|
||||||
|
onClose={closeModal}
|
||||||
|
onSubmit={handleTabSave}
|
||||||
|
/>
|
||||||
|
<DeleteFilterTabDialog
|
||||||
|
open={params.action === "delete-search"}
|
||||||
|
confirmButtonState="default"
|
||||||
|
onClose={closeModal}
|
||||||
|
onSubmit={handleTabDelete}
|
||||||
|
tabName={maybe(() => tabs[currentTab - 1].name, "...")}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
31
src/staff/views/StaffList/filter.ts
Normal file
31
src/staff/views/StaffList/filter.ts
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
import { StaffUserInput } from "@saleor/types/globalTypes";
|
||||||
|
import {
|
||||||
|
createFilterTabUtils,
|
||||||
|
createFilterUtils
|
||||||
|
} from "../../../utils/filters";
|
||||||
|
import {
|
||||||
|
StaffListUrlFilters,
|
||||||
|
StaffListUrlFiltersEnum,
|
||||||
|
StaffListUrlQueryParams
|
||||||
|
} from "../../urls";
|
||||||
|
|
||||||
|
export const STAFF_FILTERS_KEY = "staffFilters";
|
||||||
|
|
||||||
|
export function getFilterVariables(
|
||||||
|
params: StaffListUrlFilters
|
||||||
|
): StaffUserInput {
|
||||||
|
return {
|
||||||
|
search: params.query
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const {
|
||||||
|
deleteFilterTab,
|
||||||
|
getFilterTabs,
|
||||||
|
saveFilterTab
|
||||||
|
} = createFilterTabUtils<StaffListUrlFilters>(STAFF_FILTERS_KEY);
|
||||||
|
|
||||||
|
export const { areFiltersApplied, getActiveFilters } = createFilterUtils<
|
||||||
|
StaffListUrlQueryParams,
|
||||||
|
StaffListUrlFilters
|
||||||
|
>(StaffListUrlFiltersEnum);
|
2
src/staff/views/StaffList/index.ts
Normal file
2
src/staff/views/StaffList/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export { default } from "./StaffList";
|
||||||
|
export * from "./StaffList";
|
|
@ -197,6 +197,11 @@ export enum ShippingMethodTypeEnum {
|
||||||
WEIGHT = "WEIGHT",
|
WEIGHT = "WEIGHT",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum StaffMemberStatus {
|
||||||
|
ACTIVE = "ACTIVE",
|
||||||
|
DEACTIVATED = "DEACTIVATED",
|
||||||
|
}
|
||||||
|
|
||||||
export enum StockAvailability {
|
export enum StockAvailability {
|
||||||
IN_STOCK = "IN_STOCK",
|
IN_STOCK = "IN_STOCK",
|
||||||
OUT_OF_STOCK = "OUT_OF_STOCK",
|
OUT_OF_STOCK = "OUT_OF_STOCK",
|
||||||
|
@ -659,6 +664,11 @@ export interface StaffInput {
|
||||||
permissions?: (PermissionEnum | null)[] | null;
|
permissions?: (PermissionEnum | null)[] | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface StaffUserInput {
|
||||||
|
status?: StaffMemberStatus | null;
|
||||||
|
search?: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
export interface TranslationInput {
|
export interface TranslationInput {
|
||||||
seoTitle?: string | null;
|
seoTitle?: string | null;
|
||||||
seoDescription?: string | null;
|
seoDescription?: string | null;
|
||||||
|
|
Loading…
Reference in a new issue