Pular para o conteúdo

Copiando uma entidade de uma coleção para outra

Product selection

Neste tutorial vamos mostrar como você pode adicionar um botão à sua coleção, que permitirá copiar entidades de outra coleção.

É muito comum em bancos de dados NoSQL, como o Firestore, manter dados desnormalizados em diferentes coleções. Ou seja, manter as mesmas informações em múltiplos locais, em vez de bancos de dados normalizados onde as informações devem ser idealmente armazenadas apenas uma vez.

Para fins ilustrativos, vamos criar duas coleções simples de products, das quais vamos copiar de e para:

import { buildCollection, buildProperties } from "@firecms/core";
export type Product = {
name: string;
price: number;
}
// Common properties of our target and source collections
export const properties = buildProperties<Product>({
name: {
name: "Name",
validation: { required: true },
dataType: "string"
},
price: {
name: "Price",
validation: {
required: true,
min: 0
},
dataType: "number"
}
});
// Source collection
export const productsCollection = buildCollection<Product>({
name: "Products",
id: "products",
path: "products",
properties
});
// Target collection
export const productsCollectionCopy = buildCollection<Product>({
name: "Products copy target",
id: "products_copied",
path: "products_copied",
properties
});

Adicionar uma ação personalizada à sua coleção

Seção intitulada “Adicionar uma ação personalizada à sua coleção”

No próximo passo vamos adicionar um botão personalizado à nossa coleção destino. Este botão abrirá um diálogo de referência e permitirá que os usuários selecionem uma entidade na origem.

Este exemplo usa alguns hooks fornecidos pelo FireCMS para desenvolver componentes personalizados.

import { useCallback } from "react";
import { Entity, EntityCollection, useDataSource, useReferenceDialog, useSnackbarController } from "@firecms/core";
import { Button } from "@firecms/ui";
export type CopyEntityButtonProps = {
pathFrom: string;
pathTo: string;
collectionFrom: EntityCollection;
collectionTo: EntityCollection;
};
export function CopyEntityButton({
pathFrom,
collectionFrom,
pathTo,
collectionTo
}: CopyEntityButtonProps) {
// The datasource allows us to create new documents
const dataSource = useDataSource();
// We use a snackbar to indicate success
const snackbarController = useSnackbarController();
// We declare a callback function for the reference dialog that will
// create the new entity and show a snackbar when completed
const copyEntity = useCallback((entity: Entity<any> | null) => {
if (entity) {
dataSource.saveEntity({
path: pathTo,
values: entity.values,
entityId: entity.id,
collection: collectionTo,
status: "new"
}).then(() => {
snackbarController.open({
type: "success",
message: "Copied entity " + entity.id
});
});
}
}, [collectionTo, dataSource, pathTo, snackbarController]);
// This dialog is used to prompt the selected collection
const referenceDialog = useReferenceDialog({
path: pathFrom,
collection: collectionFrom,
multiselect: false,
onSingleEntitySelected: copyEntity
});
return (
<Button onClick={referenceDialog.open}>
Copy from {pathFrom}
</Button>
);
}

Depois que seu componente estiver pronto, você pode conectá-lo às Actions das suas coleções:

import { buildCollection, CollectionActionsProps } from "@firecms/core";
import { CopyEntityButton } from "./copy_button";
import { Product, productsCollection, properties } from "./simple_product_collection";
export const productsCollectionCopy = buildCollection<Product>({
id: "products_copied",
name: "Products copy target",
path: "products_copied",
properties,
Actions: ({ path, collection }: CollectionActionsProps<Product>) =>
<CopyEntityButton
pathFrom={"products"}
collectionFrom={productsCollection}
pathTo={path}
collectionTo={collection}
/>
});
import { useCallback } from "react";
import {
buildCollection,
buildProperties,
CollectionActionsProps,
Entity,
EntityCollection,
useDataSource,
useReferenceDialog,
useSnackbarController
} from "@firecms/core";
import { Button } from "@firecms/ui";
type Product = {
name: string;
price: number;
}
type CopyEntityButtonProps = {
pathFrom: string;
pathTo: string;
collectionFrom: EntityCollection<any>;
collectionTo: EntityCollection<any>;
};
function CopyEntityButton({
pathFrom,
collectionFrom,
pathTo,
collectionTo
}: CopyEntityButtonProps) {
// The datasource allows us to create new documents
const dataSource = useDataSource();
// We use a snackbar to indicate success
const snackbarController = useSnackbarController();
// We declare a callback function for the reference dialog that will
// create the new entity and show a snackbar when completed
const copyEntity = useCallback((entity: Entity<any> | null) => {
if (entity) {
dataSource.saveEntity({
path: pathTo,
values: entity.values,
entityId: entity.id,
collection: collectionTo,
status: "new"
}).then(() => {
snackbarController.open({
type: "success",
message: "Copied entity " + entity.id
});
});
}
}, [collectionTo, dataSource, pathTo, snackbarController]);
// This dialog is used to prompt the selected collection
const referenceDialog = useReferenceDialog({
path: pathFrom,
collection: collectionFrom,
multiselect: false,
onSingleEntitySelected: copyEntity
});
return (
<Button onClick={referenceDialog.open}>
Copy from {pathFrom}
</Button>
);
}
// Common properties of our target and source collections
const properties = buildProperties<Product>({
name: {
name: "Name",
validation: { required: true },
dataType: "string"
},
price: {
name: "Price",
validation: {
required: true,
min: 0
},
dataType: "number"
}
});
// Source collection
export const productsCollection = buildCollection<Product>({
name: "Products",
id: "products",
path: "products",
properties
});
// Target collection
export const productsCollectionCopy = buildCollection<Product>({
name: "Products copy target",
id: "products_copied",
path: "products_copied",
properties,
Actions: ({ path, collection }: CollectionActionsProps<Product>) =>
<CopyEntityButton
pathFrom={"products"}
collectionFrom={productsCollection}
pathTo={path}
collectionTo={collection}
/>
});