diff --git a/src/services/components/ServiceDetailsPage/ServiceDetailsPage.tsx b/src/services/components/ServiceDetailsPage/ServiceDetailsPage.tsx index c1354f449..9c6bcf9e9 100644 --- a/src/services/components/ServiceDetailsPage/ServiceDetailsPage.tsx +++ b/src/services/components/ServiceDetailsPage/ServiceDetailsPage.tsx @@ -97,14 +97,20 @@ const ServiceDetailsPage: React.FC = props => { onDelete={onTokenDelete} /> - - - +
+ + + +
void; } @@ -51,10 +51,13 @@ const styles = (theme: Theme) => }, table: { tableLayout: "fixed" + }, + tableRow: { + cursor: "pointer" } }); -const numberOfColumns = 3; +const numberOfColumns = 2; const ServiceList = withStyles(styles, { name: "ServiceList" @@ -69,24 +72,12 @@ const ServiceList = withStyles(styles, { onRemove, onRowClick, pageInfo, - services, - isChecked, - selected, - toggle, - toggleAll, - toolbar + services }: ServiceListProps & WithStyles) => ( - + - + @@ -108,62 +99,49 @@ const ServiceList = withStyles(styles, { {renderCollection( services, - service => { - const isSelected = service ? isChecked(service.id) : false; - - return ( - - - toggle(service.id)} - /> - - - - {maybe(() => service.name, )} - - - {maybe(() => - service.isActive ? ( - - ) : ( - - ) - )} - - - - - - - onRemove(service.id) : undefined} - > - - - - - ); - }, + service => ( + + + + {maybe(() => service.name, )} + + + {maybe(() => + service.isActive ? ( + + ) : ( + + ) + )} + + + + + + + onRemove(service.id) : undefined} + > + + + + + ), () => ( diff --git a/src/services/components/ServiceListPage/ServiceListPage.tsx b/src/services/components/ServiceListPage/ServiceListPage.tsx index 1a3394331..e1ef0bf78 100644 --- a/src/services/components/ServiceListPage/ServiceListPage.tsx +++ b/src/services/components/ServiceListPage/ServiceListPage.tsx @@ -8,18 +8,12 @@ import Container from "@saleor/components/Container"; import PageHeader from "@saleor/components/PageHeader"; import SearchBar from "@saleor/components/SearchBar"; import { sectionNames } from "@saleor/intl"; -import { - ListActions, - PageListProps, - SearchPageProps, - TabPageProps -} from "@saleor/types"; +import { PageListProps, SearchPageProps, TabPageProps } from "@saleor/types"; import { ServiceList_serviceAccounts_edges_node } from "../../types/ServiceList"; import ServiceList from "../ServiceList"; export interface ServiceListPageProps extends PageListProps, - ListActions, SearchPageProps, TabPageProps { services: ServiceList_serviceAccounts_edges_node[]; diff --git a/src/services/index.tsx b/src/services/index.tsx index e2d950ca9..aa9693fec 100644 --- a/src/services/index.tsx +++ b/src/services/index.tsx @@ -6,11 +6,13 @@ import { Route, RouteComponentProps, Switch } from "react-router-dom"; import { sectionNames } from "@saleor/intl"; import { WindowTitle } from "../components/WindowTitle"; import { + serviceAddPath, serviceListPath, ServiceListUrlQueryParams, servicePath, ServiceUrlQueryParams } from "./urls"; +import ServiceCreate from "./views/ServiceCreate"; import ServiceDetailsComponent from "./views/ServiceDetails"; import ServiceListComponent from "./views/ServiceList"; @@ -43,6 +45,7 @@ const ServiceSection = () => { + diff --git a/src/services/mutations.ts b/src/services/mutations.ts new file mode 100644 index 000000000..cbec091e5 --- /dev/null +++ b/src/services/mutations.ts @@ -0,0 +1,24 @@ +import gql from "graphql-tag"; + +import { TypedMutation } from "../mutations"; +import { serviceFragment } from "./queries"; +import { ServiceCreate, ServiceCreateVariables } from "./types/ServiceCreate"; + +export const serviceCreateMutation = gql` + ${serviceFragment} + mutation ServiceCreate($input: ServiceAccountInput!) { + serviceAccountCreate(input: $input) { + errors { + field + message + } + serviceAccount { + ...ServiceFragment + } + } + } +`; +export const ServiceCreateMutation = TypedMutation< + ServiceCreate, + ServiceCreateVariables +>(serviceCreateMutation); diff --git a/src/services/queries.ts b/src/services/queries.ts index 13dff2f79..f7327fc50 100644 --- a/src/services/queries.ts +++ b/src/services/queries.ts @@ -37,6 +37,9 @@ const serviceList = gql` ...ServiceFragment } } + pageInfo { + ...PageInfoFragment + } } } `; diff --git a/src/services/types/ServiceCreate.ts b/src/services/types/ServiceCreate.ts new file mode 100644 index 000000000..3f5cde471 --- /dev/null +++ b/src/services/types/ServiceCreate.ts @@ -0,0 +1,36 @@ +/* tslint:disable */ +/* eslint-disable */ +// This file was automatically generated and should not be edited. + +import { ServiceAccountInput } from "./../../types/globalTypes"; + +// ==================================================== +// GraphQL mutation operation: ServiceCreate +// ==================================================== + +export interface ServiceCreate_serviceAccountCreate_errors { + __typename: "Error"; + field: string | null; + message: string | null; +} + +export interface ServiceCreate_serviceAccountCreate_serviceAccount { + __typename: "ServiceAccount"; + id: string; + name: string | null; + isActive: boolean | null; +} + +export interface ServiceCreate_serviceAccountCreate { + __typename: "ServiceAccountCreate"; + errors: ServiceCreate_serviceAccountCreate_errors[] | null; + serviceAccount: ServiceCreate_serviceAccountCreate_serviceAccount | null; +} + +export interface ServiceCreate { + serviceAccountCreate: ServiceCreate_serviceAccountCreate | null; +} + +export interface ServiceCreateVariables { + input: ServiceAccountInput; +} diff --git a/src/services/types/ServiceList.ts b/src/services/types/ServiceList.ts index d32a5b070..4e5c413c3 100644 --- a/src/services/types/ServiceList.ts +++ b/src/services/types/ServiceList.ts @@ -20,9 +20,18 @@ export interface ServiceList_serviceAccounts_edges { node: ServiceList_serviceAccounts_edges_node; } +export interface ServiceList_serviceAccounts_pageInfo { + __typename: "PageInfo"; + endCursor: string | null; + hasNextPage: boolean; + hasPreviousPage: boolean; + startCursor: string | null; +} + export interface ServiceList_serviceAccounts { __typename: "ServiceAccountCountableConnection"; edges: ServiceList_serviceAccounts_edges[]; + pageInfo: ServiceList_serviceAccounts_pageInfo; } export interface ServiceList { diff --git a/src/services/views/ServiceCreate/ServiceCreate.tsx b/src/services/views/ServiceCreate/ServiceCreate.tsx new file mode 100644 index 000000000..cbd11300f --- /dev/null +++ b/src/services/views/ServiceCreate/ServiceCreate.tsx @@ -0,0 +1,71 @@ +import React from "react"; +import { useIntl } from "react-intl"; + +import { WindowTitle } from "@saleor/components/WindowTitle"; +import useNavigator from "@saleor/hooks/useNavigator"; +import useNotifier from "@saleor/hooks/useNotifier"; +import useShop from "@saleor/hooks/useShop"; +import { commonMessages } from "@saleor/intl"; +import { getMutationState, maybe } from "@saleor/misc"; +import { ServiceCreateMutation } from "@saleor/services/mutations"; +import ServiceCreatePage, { + ServiceCreatePageFormData +} from "../../components/ServiceCreatePage"; +import { serviceListUrl, serviceUrl, ServiceUrlQueryParams } from "../../urls"; + +export const ServiceCreate: React.StatelessComponent = () => { + const navigate = useNavigator(); + const notify = useNotifier(); + const intl = useIntl(); + const shop = useShop(); + + const onSubmit = () => undefined; + + const handleBack = () => navigate(serviceListUrl()); + + return ( + + {(serviceCreate, serviceCreateOpts) => { + const handleSubmit = (data: ServiceCreatePageFormData) => + serviceCreate({ + variables: { + input: { + isActive: data.isActive, + name: data.name, + permissions: data.hasFullAccess + ? shop.permissions.map(permission => permission.code) + : data.permissions + } + } + }); + + const formTransitionState = getMutationState( + serviceCreateOpts.called, + serviceCreateOpts.loading, + maybe(() => serviceCreateOpts.data.serviceAccountCreate.errors) + ); + + return ( + <> + + shop.permissions)} + saveButtonBarState={formTransitionState} + /> + + ); + }} + + ); +}; + +export default ServiceCreate; diff --git a/src/services/views/ServiceCreate/index.ts b/src/services/views/ServiceCreate/index.ts new file mode 100644 index 000000000..a6de9b346 --- /dev/null +++ b/src/services/views/ServiceCreate/index.ts @@ -0,0 +1,2 @@ +export { default } from "./ServiceCreate"; +export * from "./ServiceCreate"; diff --git a/src/services/views/ServiceDetails/ServiceDetails.tsx b/src/services/views/ServiceDetails/ServiceDetails.tsx index 25fd059e7..da4904306 100644 --- a/src/services/views/ServiceDetails/ServiceDetails.tsx +++ b/src/services/views/ServiceDetails/ServiceDetails.tsx @@ -11,7 +11,12 @@ import ServiceDetailsPage, { ServiceDetailsPageFormData } from "../../components/ServiceDetailsPage"; import { ServiceDetailsQuery } from "../../queries"; -import { serviceListUrl, serviceUrl, ServiceUrlQueryParams } from "../../urls"; +import { + serviceListUrl, + serviceUrl, + ServiceUrlDialog, + ServiceUrlQueryParams +} from "../../urls"; interface OrderListProps { id: string; @@ -27,6 +32,25 @@ export const ServiceDetails: React.StatelessComponent = ({ const intl = useIntl(); const shop = useShop(); + const closeModal = () => + navigate( + serviceUrl(id, { + ...params, + action: undefined, + id: undefined + }), + true + ); + + const openModal = (action: ServiceUrlDialog, tokenId?: string) => + navigate( + serviceUrl(id, { + ...params, + action, + id: tokenId + }) + ); + return ( = ({ } }; - const handleBack = navigate(serviceListUrl()); - - const handleDelete = navigate( - serviceUrl(id, { - ...params, - action: "remove" - }) - ); + const handleBack = () => navigate(serviceListUrl()); const handleSubmit = (data: ServiceDetailsPageFormData) => undefined; @@ -68,8 +85,10 @@ export const ServiceDetails: React.StatelessComponent = ({ disabled={loading} errors={[]} onBack={handleBack} - onDelete={handleDelete} + onDelete={() => openModal("remove")} onSubmit={handleSubmit} + onTokenCreate={() => openModal("create-token")} + onTokenDelete={() => openModal("delete-token")} permissions={maybe(() => shop.permissions)} service={maybe(() => data.serviceAccount)} saveButtonBarState="default" diff --git a/src/services/views/ServiceList/ServiceList.tsx b/src/services/views/ServiceList/ServiceList.tsx index 4ff43e746..9cd843fe6 100644 --- a/src/services/views/ServiceList/ServiceList.tsx +++ b/src/services/views/ServiceList/ServiceList.tsx @@ -20,6 +20,7 @@ import { ListViews } from "@saleor/types"; import ServiceListPage from "../../components/ServiceListPage"; import { ServiceListQuery } from "../../queries"; import { + serviceAddUrl, serviceListUrl, ServiceListUrlDialog, ServiceListUrlFilters, @@ -118,72 +119,50 @@ export const ServiceList: React.StatelessComponent = ({ return ( - {({ data, loading }) => ( - - {(addServiceMember, addServiceMemberData) => { - const handleServiceMemberAdd = (variables: AddServiceMemberForm) => - addServiceMember({ - variables: { - input: { - email: variables.email, - firstName: variables.firstName, - lastName: variables.lastName, - permissions: variables.fullAccess - ? maybe(() => shop.permissions.map(perm => perm.code)) - : undefined, - sendPasswordEmail: true - } - } - }); - const addTransitionState = getMutationState( - addServiceMemberData.called, - addServiceMemberData.loading, - maybe(() => addServiceMemberData.data.serviceCreate.errors) - ); + {({ data, loading }) => { + const { loadNextPage, loadPreviousPage, pageInfo } = paginate( + maybe(() => data.serviceAccounts.pageInfo), + paginationState, + params + ); - const { loadNextPage, loadPreviousPage, pageInfo } = paginate( - maybe(() => data.serviceUsers.pageInfo), - paginationState, - params - ); + const handleCreate = () => navigate(serviceAddUrl); + const handleRemove = () => + navigate( + serviceListUrl({ + ...params, + action: "remove" + }) + ); - return ( - <> - changeFilterField({ query })} - onAll={() => navigate(serviceListUrl())} - onTabChange={handleTabChange} - onTabDelete={() => openModal("delete-search")} - onTabSave={() => openModal("save-search")} - tabs={tabs.map(tab => tab.name)} - disabled={loading || addServiceMemberData.loading} - settings={settings} - pageInfo={pageInfo} - serviceMembers={maybe(() => - data.serviceUsers.edges.map(edge => edge.node) - )} - onAdd={() => - navigate( - serviceListUrl({ - action: "add" - }) - ) - } - onBack={() => navigate(configurationMenuUrl)} - onNextPage={loadNextPage} - onPreviousPage={loadPreviousPage} - onUpdateListSettings={updateListSettings} - onRowClick={id => () => navigate(serviceUrl(id))} - /> - - ); - }} - - )} + return ( + <> + changeFilterField({ query })} + onAll={() => navigate(serviceListUrl())} + onTabChange={handleTabChange} + onTabDelete={() => openModal("delete-search")} + onTabSave={() => openModal("save-search")} + tabs={tabs.map(tab => tab.name)} + disabled={loading} + settings={settings} + pageInfo={pageInfo} + services={maybe(() => + data.serviceAccounts.edges.map(edge => edge.node) + )} + onAdd={handleCreate} + onBack={() => navigate(configurationMenuUrl)} + onNextPage={loadNextPage} + onPreviousPage={loadPreviousPage} + onUpdateListSettings={updateListSettings} + onRowClick={id => () => navigate(serviceUrl(id))} + onRemove={handleRemove} + /> + + ); + }} ); }; diff --git a/src/services/views/ServiceList/filter.ts b/src/services/views/ServiceList/filter.ts new file mode 100644 index 000000000..a1d2b7724 --- /dev/null +++ b/src/services/views/ServiceList/filter.ts @@ -0,0 +1,31 @@ +import { ServiceAccountFilterInput } from "@saleor/types/globalTypes"; +import { + createFilterTabUtils, + createFilterUtils +} from "../../../utils/filters"; +import { + ServiceListUrlFilters, + ServiceListUrlFiltersEnum, + ServiceListUrlQueryParams +} from "../../urls"; + +export const STAFF_FILTERS_KEY = "staffFilters"; + +export function getFilterVariables( + params: ServiceListUrlFilters +): ServiceAccountFilterInput { + return { + search: params.query + }; +} + +export const { + deleteFilterTab, + getFilterTabs, + saveFilterTab +} = createFilterTabUtils(STAFF_FILTERS_KEY); + +export const { areFiltersApplied, getActiveFilters } = createFilterUtils< + ServiceListUrlQueryParams, + ServiceListUrlFilters +>(ServiceListUrlFiltersEnum); diff --git a/src/types/globalTypes.ts b/src/types/globalTypes.ts index e4a258330..cf5449769 100644 --- a/src/types/globalTypes.ts +++ b/src/types/globalTypes.ts @@ -655,6 +655,12 @@ export interface ServiceAccountFilterInput { isActive?: boolean | null; } +export interface ServiceAccountInput { + name?: string | null; + isActive?: boolean | null; + permissions?: (PermissionEnum | null)[] | null; +} + export interface ShippingPriceInput { name?: string | null; price?: any | null;