Skip to content

Commit

Permalink
Demo: Add custom more actions to handmade products grid (#3259)
Browse files Browse the repository at this point in the history
Co-authored-by: Ricky James Smith <[email protected]>
  • Loading branch information
johnnyomair and jamesricky authored Feb 4, 2025
1 parent 332e3f3 commit 711958c
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 4 deletions.
56 changes: 52 additions & 4 deletions demo/admin/src/products/ProductsGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,15 @@ import {
useDataGridRemote,
usePersistentColumnState,
} from "@comet/admin";
import { Add as AddIcon, Edit, Excel, StateFilled as StateFilledIcon } from "@comet/admin-icons";
import { Add as AddIcon, Disabled, Edit, Excel, Online, StateFilled as StateFilledIcon } from "@comet/admin-icons";
import { DamImageBlock } from "@comet/cms-admin";
import { CircularProgress, IconButton, useTheme } from "@mui/material";
import { DataGridPro, GridFilterInputSingleSelect, GridFilterInputValue, GridToolbarQuickFilter } from "@mui/x-data-grid-pro";
import { DataGridPro, GridFilterInputSingleSelect, GridFilterInputValue, GridSelectionModel, GridToolbarQuickFilter } from "@mui/x-data-grid-pro";
import gql from "graphql-tag";
import { useState } from "react";
import { FormattedMessage, FormattedNumber, useIntl } from "react-intl";

import { PublishAllProducts } from "./helpers/PublishAllProducts";
import { ManufacturerFilterOperator } from "./ManufacturerFilter";
import {
GQLCreateProductMutation,
Expand All @@ -48,7 +50,10 @@ import {
} from "./ProductsGrid.generated";
import { ProductsGridPreviewAction } from "./ProductsGridPreviewAction";

function ProductsGridToolbar({ exportApi }: { exportApi: ExportApi }) {
function ProductsGridToolbar({ exportApi, selectionModel }: { exportApi: ExportApi; selectionModel: GridSelectionModel }) {
const client = useApolloClient();
const theme = useTheme();

return (
<DataGridToolbar>
<ToolbarItem>
Expand All @@ -70,7 +75,43 @@ function ProductsGridToolbar({ exportApi }: { exportApi: ExportApi }) {
onClick: () => exportApi.exportGrid(),
disabled: exportApi.loading,
},
<PublishAllProducts key="publish" />,
]}
selectiveActions={[
{
label: "Publish",
icon: <Online htmlColor={theme.palette.success.main} />,
onClick: () => {
for (const id of selectionModel) {
client.mutate<GQLUpdateProductStatusMutation, GQLUpdateProductStatusMutationVariables>({
mutation: updateProductStatusMutation,
variables: { id: id as string, status: "Published" },
optimisticResponse: {
__typename: "Mutation",
updateProduct: { __typename: "Product", id: id as string, status: "Published" },
},
});
}
},
},
{
label: "Unpublish",
icon: <Disabled />,
onClick: () => {
for (const id of selectionModel) {
client.mutate<GQLUpdateProductStatusMutation, GQLUpdateProductStatusMutationVariables>({
mutation: updateProductStatusMutation,
variables: { id: id as string, status: "Unpublished" },
optimisticResponse: {
__typename: "Mutation",
updateProduct: { __typename: "Product", id: id as string, status: "Unpublished" },
},
});
}
},
},
]}
selectionSize={selectionModel.length}
/>
<Button responsive startIcon={<AddIcon />} component={StackLink} pageName="add" payload="add">
<FormattedMessage id="products.newProduct" defaultMessage="New Product" />
Expand All @@ -87,6 +128,7 @@ export function ProductsGrid() {
const { data: relationsData } = useQuery<GQLProductGridRelationsQuery, GQLProductGridRelationsQueryVariables>(productRelationsQuery);
const intl = useIntl();
const theme = useTheme();
const [selectionModel, setSelectionModel] = useState<GridSelectionModel>([]);

const columns: GridColDef<GQLProductsListManualFragment>[] = [
{
Expand Down Expand Up @@ -347,7 +389,13 @@ export function ProductsGrid() {
Toolbar: ProductsGridToolbar,
}}
componentsProps={{
toolbar: { exportApi },
toolbar: { exportApi, selectionModel },
}}
checkboxSelection
keepNonExistentRowsSelected
selectionModel={selectionModel}
onSelectionModelChange={(selectionModel) => {
setSelectionModel(selectionModel);
}}
/>
);
Expand Down
56 changes: 56 additions & 0 deletions demo/admin/src/products/helpers/PublishAllProducts.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { gql, useApolloClient } from "@apollo/client";
import { Button, CancelButton, CrudMoreActionsMenuContext, Dialog } from "@comet/admin";
import { Online } from "@comet/admin-icons";
import { DialogActions, DialogContent, ListItemIcon, MenuItem } from "@mui/material";
import { useContext, useState } from "react";

import { GQLPublishAllProductsMutation, GQLPublishAllProductsMutationVariables } from "./PublishAllProducts.generated";

export function PublishAllProducts() {
const [open, setOpen] = useState(false);
const client = useApolloClient();
const { closeMenu } = useContext(CrudMoreActionsMenuContext);

const handlePublishAll = async () => {
await client.mutate<GQLPublishAllProductsMutation, GQLPublishAllProductsMutationVariables>({
mutation: gql`
mutation PublishAllProducts {
publishAllProducts
}
`,
});

client.cache.evict({ fieldName: "products" });

handleClose();
};

const handleClose = () => {
setOpen(false);
closeMenu();
};

return (
<>
<MenuItem
onClick={() => {
setOpen(true);
}}
>
<ListItemIcon>
<Online color="success" />
</ListItemIcon>
Publish all...
</MenuItem>
<Dialog open={open} onClose={handleClose} title="Publish all products?">
<DialogContent>You are about to publish all products.</DialogContent>
<DialogActions>
<CancelButton onClick={handleClose} />
<Button onClick={handlePublishAll} startIcon={<Online />} variant="success">
Publish
</Button>
</DialogActions>
</Dialog>
</>
);
}
1 change: 1 addition & 0 deletions demo/api/schema.gql
Original file line number Diff line number Diff line change
Expand Up @@ -1239,6 +1239,7 @@ type Mutation {
createManufacturer(input: ManufacturerInput!): Manufacturer!
updateManufacturer(id: ID!, input: ManufacturerUpdateInput!): Manufacturer!
deleteManufacturer(id: ID!): Boolean!
publishAllProducts: Boolean!
}

input UserPermissionInput {
Expand Down
18 changes: 18 additions & 0 deletions demo/api/src/products/custom-product.resolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { RequiredPermission } from "@comet/cms-api";
import { InjectRepository } from "@mikro-orm/nestjs";
import { EntityRepository } from "@mikro-orm/postgresql";
import { Mutation, Resolver } from "@nestjs/graphql";

import { Product, ProductStatus } from "./entities/product.entity";

@Resolver(() => Product)
@RequiredPermission(["products"], { skipScopeCheck: true })
export class CustomProductResolver {
constructor(@InjectRepository(Product) private readonly repository: EntityRepository<Product>) {}

@Mutation(() => Boolean)
async publishAllProducts(): Promise<boolean> {
await this.repository.nativeUpdate({ status: { $ne: ProductStatus.Published } }, { status: ProductStatus.Published });
return true;
}
}
2 changes: 2 additions & 0 deletions demo/api/src/products/products.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { MikroOrmModule } from "@mikro-orm/nestjs";
import { Module } from "@nestjs/common";
import { ProductVariantsService } from "@src/products/generated/product-variants.service";

import { CustomProductResolver } from "./custom-product.resolver";
import { Manufacturer } from "./entities/manufacturer.entity";
import { ManufacturerCountry } from "./entities/manufacturer-country.entity";
import { Product } from "./entities/product.entity";
Expand Down Expand Up @@ -46,6 +47,7 @@ import { ProductVariantResolver } from "./generated/product-variant.resolver";
ManufacturerResolver,
ManufacturerCountryResolver,
ProductToTagResolver,
CustomProductResolver,
],
exports: [],
})
Expand Down

0 comments on commit 711958c

Please sign in to comment.