I'm very new to Polaris/Shopify and need some help with a problem.
I'm using <IndexTable /> to create a list of offers for our store, which uses promotedBulkActions.
These are all working fine and the API calls are happening as expected. My problem is that I need to make the content dynamic. For example, if a user deletes an entry I'd like the row to disappear or if they toggle the state of an entry, I'd like to see the status change automagically.
I got the original information from:
https://polaris.shopify.com/components/index-table
...which has worked fine, but it's only using static data.
The data itself is called from a custom API endpoint then parsed into a variable rowMarkup. I think it should have something to do with useState but I'm just struggling with the last bit.
My current code (with the unimportant bits removed) is:
import {
Card,
IndexTable,
useIndexResourceState,
Filters,
TextField
} from "@shopify/polaris";
import { useAppQuery, useAuthenticatedFetch } from "../hooks";
import { useState, useCallback } from 'react';
import { useEffect, useLayoutEffect } from "react";
import { TitleBar, useNavigate } from "@shopify/app-bridge-react";
import { data } from "@shopify/app-bridge/actions/Modal";
export function OfferTabs() {
const [offers, setOffers] = useState([]);
const [taggedWith, setTaggedWith] = useState('current');
const [offerList, setOfferList] = useState([]);
const [selected, setSelected] = useState(0);
const [active, setActive] = useState(false);
const [statusText, setStatusText] = useState('Active');
const [status, setStatus] = useState(1);
const navigate = useNavigate();
useLayoutEffect(() => {
fetch("xxxxx")
.then(res => res.json())
.then(result => {
setOffers(result);
});
}, []);
// const fetch = useAuthenticatedFetch();
const getStatusText = (status) => {
const _t = (status === 1) ? 'Active' : 'Inactive';
// setStatus(_t);
return _t;
}
const getContent = (type) => {
let _return = [];
Object.keys(offers).map(o => {
offers[o].map(m => {
_return.push(
{
id: m.id,
name: m.name,
type: m.type,
start_date: m.start_date,
end_date: m.end_date,
status: m.status,
status_text: getStatusText(m.status),
shopify_id: m.shopify_id,
offer_type: o
}
);
});
});
return _return;
}
/* handling functions */
const handleDelete = () => {
const _itemCount = selectedResources.length;
const _qtyStr = (_itemCount === 1) ? "this item" : `these ${_itemCount} items`
if (confirm(`Do you want to delete ${_qtyStr}?\nThis cannot be undone!`)) {
const _queryData = selectedResources.join(",");
const _queryURL = `xxxx`;
const _headers = {'method':'DELETE'}
/* send the request and remove the elements from the DOM */
fetch(_queryURL,_headers)
.then(()=> {
console.log("TO DO: Auto-refresh the content");
});
}
}
const handleStatusChange = (v) => {
const _itemCount = selectedResources.length;
const _qtyStr = (_itemCount === 1) ? "this item" : `these ${_itemCount} items`
if (confirm(`Do you want to change the status of ${_qtyStr}?`)) {
const _queryData = selectedResources.join(",");
const _queryURL = `https://xxxxx`;
const _headers = { 'method': 'PUT' }
fetch(_queryURL,_headers)
.then(()=> {
console.log("TO DO: Auto-refresh the content");
});
}
}
/* this will convert the offers data into the correct format for an IndexTable */
const indexContent = getContent();
const resourceName = {
singular: 'promotion',
plural: 'promotions',
};
const { selectedResources, allResourcesSelected, handleSelectionChange } =
useIndexResourceState(indexContent);
const rowMarkup = indexContent.map(
({ id, name, type, start_date, end_date, status, status_text, offer_type }, index) => (
<IndexTable.Row
id={id}
key={id}
selected={selectedResources.includes(id)}
position={index}
>
<IndexTable.Cell>{name}</IndexTable.Cell>
<IndexTable.Cell>{type}</IndexTable.Cell>
<IndexTable.Cell>{start_date}</IndexTable.Cell>
<IndexTable.Cell>{end_date}</IndexTable.Cell>
<IndexTable.Cell>{offer_type}</IndexTable.Cell>
<IndexTable.Cell>{status_text}</IndexTable.Cell>
</IndexTable.Row>
),
);
const promotedBulkActions = [
{
title: "Change Status",
actions: [
{
content: 'Activate',
onAction: () => handleStatusChange(1)
},
{
content: 'Deactivate',
onAction: () => handleStatusChange(0)
}
]
},
{
title: "Other Actions",
actions: [
{
content: 'Delete',
onAction: handleDelete
}
]
}
];
return (
<Card>
<IndexTable
resourceName={resourceName}
itemCount={indexContent.length}
selectedItemsCount={
allResourcesSelected ? 'All' : selectedResources.length
}
onSelectionChange={handleSelectionChange}
promotedBulkActions={promotedBulkActions}
headings={[
{ title: 'Name' },
{ title: 'Type' },
{ title: 'Start Date' },
{ title: 'End Date' },
{ title: 'Schedule' },
{ title: 'Status' }
]}
>
{rowMarkup}
</IndexTable>
</Card>
)
}
I'd like to know if it's possible to make the {rowMarkup} content dynamic.
Thanks.
What I did:
- Selected a row
- Performed action ("Activate")
What I expected:
The selected row to update
What happened
The API call was successful but the row didn't update.