Skip to main content

useProtrakAPI

Reference

useProtrakApi hook simplifies the code by encapsulating the boilerplate and authentication required to make a Protrak REST API call.

const { protrakUtils, protrakComponents } 
= React.useContext(customWidgetContext);
const { useProtrakApi } = protrakUtils;

const { state, run } = useProtrakApi({
requestConfig: getInstancesPromise,
instanceId
});

Parameters

  • First parameters should be a function that returns an object with following properties:
    • requestConfig: Provides a declarative way to specify the API to be called. The endpoint should be a valid Protrak API endpoint.
    • The config can be used to provider other parameters that will be passed in request. Any args will be passed as a parameter object to the config function. Notice how instanceId is passed in below example.
      const getInstancesPromise = ({ instanceId }) => {
      return {
      endpoint: `instances/${instanceId}/relatedInstances`,
      config: {
      method: 'GET',
      params: {
      'attributes[0]': 'Efforts',
      skip: 0,
      take: 9999,
      },
      },
      };
      };

      const { protrakUtils, protrakComponents }
      = React.useContext(customWidgetContext);
      const { useProtrakApi } = protrakUtils;

      const { state: response } = useProtrakApi({
      requestConfig: getInstancesPromise,
      instanceId,
      });

    • promiseFn: If you want to create a custom Promise combining or chaining multiple API calls, then use promiseFn.
    • To invoke Protrak APIs, another util protrakApiClient needs to be used. See example code below:
        const { state, run } = useProtrakApi({
      promiseFn: getPatentsPromise,
      instanceId,
      params: {
      instanceTypeName: instanceType,
      attributes: ['Name', 'TrackingId'],
      }
      });

      const getPatentsPromise = async ({ instanceId, params }) => {
      let endpoint = `instances/${instanceId}`;
      let res = await providedProtrakUtils.protrakApiClient(endpoint, {
      method: 'GET',
      params: params,
      });
      return res;
      };
    • args: Any additional properties or args will be passed as a parameter object to the config function.
  • Second parameter allows user to pass options object
    • defer: boolean value that decides whether or not the promise should be immediately invoked on render. True value indicates that the promise will not be immediately invoked. To invoke a deferred promise, use the run method in the returned object.
    • initialData: Any object passed as initialData will be returned as state.data immediately after the useProtrakAPI is called. In subsequent renders, the state.data will be overwritten with the API response.
  • onSuccess: A callback function can be passed when the promise is executed successfully. The response.data will be passed to this callback.
  • onError: A callback function can be passed when the promise is executed successfully. The response error will be passed to this callback.

Returns

useProtrakApi returns an Object with following properties:

  • state: State is an object that contains:
    • isLoading: Boolean to indicate whether the promise execution is in progress.
    • isError: Boolean to indicate whether the promise execution has failed.
    • data: Object containing promise return value (API response, typically)
    • isFulfilled: Boolean to indicate whether the promise execution is completed successfully.
  • run: A function that can be called to trigger execution of the promise. Typically used along with the defer: true option.
  • resetState: A function that can be called to reset the execution state.
  • abort: A function that can be called to abort an ongoing promise execution.

Caveats

  • Ensure that the functions promiseFn and requestConfig are defined outside of the custom widget function, to ensure that their identity does not change on re-renders. If the function identity changes on every render, it will trigger an infinite rendering loop.
  • Use only one of requestConfig and promiseFn. If requestConfig is passed, the promiseFn even if passed is ignored.
  • Ensure that loading and error states are handled correctly, showing appropriate feedback to the user.

Usage

const getInstancesPromise = ({ instanceId }) => {
return {
endpoint: `instances/${instanceId}/relatedInstances`,
config: {
method: 'GET',
params: {
'attributes[0]': 'Efforts',
'RelationFilters[0].TypeName': 'ProjectAllocation',
skip: 0,
take: 9999
}
}
};
};

function CumulativeEffortWidget(pageContext) {
const { instanceType, instanceId } = pageContext;
const { protrakUtils, protrakComponents }
= React.useContext(customWidgetContext);
const { useProtrakApi } = protrakUtils;

const { state: response } = useProtrakApi({
requestConfig: getInstancesPromise,
instanceId
});

function getCumulativeEffort(items) {
//business logic here
}

const { Spinner, Box } = protrakComponents;

if (response.isLoading) {
return (
<Box padding="1rem">
<Spinner />
</Box>
);
}

if (response.isError) {
return (
<Box padding="1rem">
<h3>Server error!</h3>
</Box>
);
}

if (response.data) {
if (!response.data.items || !response.data.items.length) {
return (
<Box padding="1rem">
<h3>No tasks found!</h3>
</Box>
);
}
const [submittedEffort, approvedEffort]
= getCumulativeEffort(response.data.items);
return (
<Box padding="1rem" direction="Column">
<h3>Count of tasks: {response.data.totalCount}</h3>
<h3>Submitted effort (hours): {submittedEffort}</h3>
<h3>Approved effort (hours): {approvedEffort}</h3>
<h3>Total effort (hours): {submittedEffort + approvedEffort}</h3>
</Box>
);
}

return null;
}

Troubleshooting

  • The API calls are authenticated with the logged-in user's context. Ensure that the user has necessary access and permissions for the instance or instances being processed in the custom widget.
  • Ensure that the promise functions are not recreated on every render to avoid infinite render loops.
  • Examine the request parameters in browser devtools to debug that correct request is being made to the server.