Displaying Entities Created from a New Definition in Sitecore Content Hub Using an External React Component (Part 2)

Hello Sitecorians, 👋In Part 1 of our blog series, we explored how to create a new definition in Sitecore Content Hub and how it can be leveraged to store and manage specific types of content. In this post, we will continue from where we left off by demonstrating how to display the entities created from this definition using an external React component.


Prerequisite

Before diving into code, let’s review the API that retrieves entities created from the newly defined MarketingCampaign:

You can use this API endpoint to fetch all entities:

https://{your-sitecore-content-hub-url}/api/entitydefinitions/MarketingCampaign/entities?take=100


This API will return a list of all entities created under the "MarketingCampaign" definition. Here's an example of what a response might look like:


{
  "items": [
    {
      "id": 58610,
      "identifier": "ei4N6v62TGiZIxT_-Fv2EA",
      "cultures": [
        "fr-FR",
        "en-US",
        "ar-AE",
        "es-US",
        "tr-TR",
        "de-DE"
      ],
      "properties": {
        "CampaignName": "Test Campaign 1",
        "StartDate": "2024-09-21T17:49:29.44Z",
        "EndDate": "2024-10-31T17:49:33.978Z",
        "Location": "US",
        "CampaignStatusActive": true,
        "PublishStatus": {
          "identifier": "PublishFailed",
          "labels": {
            "en-US": "PublishFailed"
          }
        },
        "PublishStatusDetails": "Entity definition does not exist in this schema."
      },
      "relations": { },
      "created_by": {
        "href": "https://your-sitecore-content-hub-url/api/entities/55004",
        "title": "The user who created the entity"
      },
      "created_on": "2024-09-21T17:48:28.0431451Z",
      "modified_by": {
        "href": "https://your-sitecore-content-hub-url/api/entities/6",
        "title": "The user who last modified the entity"
      },
      "modified_on": "2024-09-21T17:50:59.0222965Z",
      "entitydefinition": {
        "href": "https://your-sitecore-content-hub-url/api/entitydefinitions/MarketingCampaign",
        "title": "The entity definition for this entity"
      },
      "copy": {
        "href": "https://your-sitecore-content-hub-url/api/entities/58610/copy",
        "title": "Copy this entity"
      },
      "permissions": {
        "href": "https://your-sitecore-content-hub-url/api/entities/58610/permissions",
        "title": "The permissions on this entity"
      },
      "lifecycle": {
        "href": "https://your-sitecore-content-hub-url/api/entities/58610/lifecycle",
        "title": "The lifecycle action for this entity."
      },
      "saved_selections": {
        "href": "https://your-sitecore-content-hub-url/api/entities/58610/savedselections",
        "title": "The saved selections this entity belongs to"
      },
      "roles": {
        "href": "https://your-sitecore-content-hub-url/api/entities/58610/roles",
        "title": "Roles for this entity"
      },
      "annotations": {
        "href": "https://your-sitecore-content-hub-url/api/entities/58610/annotations",
        "title": "Annotations for this entity"
      },
      "is_root_taxonomy_item": false,
      "is_path_root": false,
      "inherits_security": true,
      "is_system_owned": false,
      "version": 3,
      "self": {
        "href": "https://your-sitecore-content-hub-url/api/entities/58610"
      },
      "renditions": { }
    }
  ],
  "total_items": 3,
  "returned_items": 3,
  "self": {
    "href": "https://your-sitecore-content-hub-url/api/entitydefinitions/MarketingCampaign/entities?take=100",
    "title": "This collection"
  }
}


Setting Up the React Component

To start, let's create a new React component called MarketingCampaigns. This component will fetch data from the MarketingCampaign definition and display it in a tabular format.

  • Create a new folder inside src/components and name it MarketingCampaigns.
  • Inside the MarketingCampaigns folder, create two files:
    • ListMarketingCampaigns.tsx
    • index.tsx
The index.tsx file sets up the React component within Sitecore Content Hub. The createExternalRoot function is responsible for rendering and unmounting the component when necessary.


import { ContentHubClient } from "@sitecore/sc-contenthub-webclient-sdk";
import { createRoot } from "react-dom/client";
import ListMarketingCampaigns from "./ListMarketingCampaigns";

interface Context {
    client: ContentHubClient
}

export default function createExternalRoot(container: HTMLElement) {
  const root = createRoot(container);

  return {
    render(context: Context) {
      root.render(
        <ListMarketingCampaigns 
        client={context.client}
        />
      );
    },

    unmount() {
      root.unmount();
    },
  };
}}

The ListMarketingCampaigns.tsx file defines the component logic for fetching and displaying the marketing campaigns.


import React, { useEffect, useState } from "react";
import { ContentHubClient } from "@sitecore/sc-contenthub-webclient-sdk";

interface Props {
  client: ContentHubClient;
}

interface Campaign {
  id: number;
  properties: {
    CampaignName: string;
    StartDate: string;
    EndDate: string;
    Location: string;
    CampaignStatusActive: boolean;
  };
}

const ListMarketingCampaigns: React.FC<Props> = ({ client }) => {
  const [campaigns, setCampaigns] = useState<Campaign[]>([]);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    const fetchCampaigns = async () => {
      try {
        const url = `/api/entitydefinitions/MarketingCampaign/entities?skip=0&take=100&sort=CreatedOn&order=desc&culture=en-US`;
        const response = await client.raw.getAsync<any>(url);

        const campaignsData: Array<Campaign> = response.content?.items;
        if (Array.isArray(campaignsData)) {
          setCampaigns(campaignsData);
        } else {
          setError("Unexpected response format.");
        }
      } catch (err) {
        setError(`Failed to fetch campaigns. Error: ${err}`);
        console.error("Error fetching campaigns:", err);
      }
    };

    fetchCampaigns();
  }, [client]);

  return (
    <div style={{ margin: '20px' }}>
      <h1>Marketing Campaigns</h1>
      {error && <p>{error}</p>}
      {campaigns.length > 0 ? (
        <div style={{ overflowX: 'auto', boxShadow: '0 4px 8px rgba(0,0,0,0.1)', borderRadius: '10px' }}>
          <table style={{ width: '100%', borderCollapse: 'collapse', borderRadius: '10px', overflow: 'hidden' }}>
            <thead>
              <tr style={{ backgroundColor: '#f8f8f8', color: '#333', textAlign: 'left' }}>
                <th style={{ padding: '12px 15px', fontWeight: '600', borderBottom: '1px solid #ddd' }}>Name</th>
                <th style={{ padding: '12px 15px', fontWeight: '600', borderBottom: '1px solid #ddd' }}>Start Date</th>
                <th style={{ padding: '12px 15px', fontWeight: '600', borderBottom: '1px solid #ddd' }}>End Date</th>
                <th style={{ padding: '12px 15px', fontWeight: '600', borderBottom: '1px solid #ddd' }}>Location</th>
                <th style={{ padding: '12px 15px', fontWeight: '600', borderBottom: '1px solid #ddd' }}>Status</th>
              </tr>
            </thead>
            <tbody>
              {campaigns.map((campaign, index) => (
                <tr
                  key={campaign.id}
                  style={{
                    backgroundColor: index % 2 === 0 ? '#f9f9f9' : '#fff',
                    transition: 'background-color 0.3s ease',
                  }}
                  onMouseEnter={(e) => (e.currentTarget.style.backgroundColor = '#f1f1f1')}
                  onMouseLeave={(e) => (e.currentTarget.style.backgroundColor = index % 2 === 0 ? '#f9f9f9' : '#fff')}
                >
                  <td style={{ padding: '12px 15px', borderBottom: '1px solid #ddd' }}>
                    {campaign.properties.CampaignName}
                  </td>
                  <td style={{ padding: '12px 15px', borderBottom: '1px solid #ddd' }}>
                    {new Date(campaign.properties.StartDate).toLocaleDateString()}
                  </td>
                  <td style={{ padding: '12px 15px', borderBottom: '1px solid #ddd' }}>
                    {new Date(campaign.properties.EndDate).toLocaleDateString()}
                  </td>
                  <td style={{ padding: '12px 15px', borderBottom: '1px solid #ddd' }}>
                    {campaign.properties.Location}
                  </td>
                  <td style={{ padding: '12px 15px', borderBottom: '1px solid #ddd' }}>
                    {campaign.properties.CampaignStatusActive ? "Active" : "Inactive"}
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      ) : (
        <p>No campaigns found.</p>
      )}
    </div>
  );
};

export default ListMarketingCampaigns;


Building the Component

Once you’ve created the component files, build it by running the following command:

npm run build --component=MarketingCampaigns

This will create a minified JavaScript file in the dist folder. This file can now be uploaded to Sitecore Content Hub.

Adding the Component to Sitecore Content Hub

To add this component to a page in Sitecore Content Hub:

  1. Navigate to Manage > Pages and select the MarketingCampaigns page.
  2. In the main zone, add an external component.


  3. Make the component visible, and select the MarketingCampaigns minified JavaScript file from the dist folder.
  4. Save your changes and refresh the page.

Now, you should see a list of all entities created from the MarketingCampaign definition, displayed in a structured and user-friendly table. Also, I have added a few more entities using the creation component. With each creation, the page automatically refreshes because I added a redirect to the creation component of the marketing campaign, allowing you to see your newly added entity immediately in the table.



Conclusion

This blog covered how to create and display entities from a new definition using an external React component in Sitecore Content Hub. By integrating the component into your pages, you can easily manage and display content based on definitions within the ecosystem. Stay tuned for the next part of this series, where we'll dive into more advanced functionalities like filtering and updating entity properties directly through the UI.😊

Post a Comment (0)
Previous Post Next Post