Prifina Components

What are Prifina components?

Like other hooks Prifina’s own hooks allow you to use many of the Prifina features and states.
The main focus is on the usePrifina hook that offers extracted logic to help you connect your custom widget or app to the Prifina platform and make it alive.
It’s always good to use the ‘latest’ for version number to stay in touch with latest releases.
"@prifina/hooks": "latest"
 

Manual installation

yarn add @prifina/hooks        # yarn
https://www.npmjs.com/package/@prifina/hooks
You can find out more about usePrifina hook in the toggle below.

usePrifina

The usePrifina hook allows the use of Prifina’s custom context value.
Creates custom context object using prifinaContext. After it returns current memoized value of the prifinaContext object with the help of React’s useMemo.
Memoized means that the cached value of a complex function is called. If the arguments of the function that is called are the same, computing of the function will not be needed again, it simply uses the stored value.
export const usePrifina = () => {
 const prifinaContext = useContext(PrifinaContext);
 const prifina = useMemo(() => {
   return prifinaContext.current;
 }, [prifinaContext]);
 return prifina;
};

Importing

import { usePrifina } from "@prifina/hooks";

Usage

Let’s see how it looks in practice.
Set yout appID which must be 10 characters long - you can claim it once you sign up as developer in App Studio or get in touch on Slack
const appID = "0123456789"; // id should be random 10 character string
 
Assign variables: onUpdate, Prifina, API, and registerHooks to usePrifina hook
const { onUpdate, Prifina, API, registerHooks } = usePrifina();
 
onUpdate, API, and registerHooks are used with useEffect hook
  • onUpdate - callback function used for background updates and notifications inside Prifina platfrom
  • API - used in await function to wait for a promise from data connectors custom query
  • registerHooks - register data source modules
useEffect(async () => {

    // init callback function for background updates/notifications
    onUpdate(appID, dataUpdate);

    // register datasource modules
    registerHooks(appID, [DataConnector]);


    const result = await API[appID].DataConnector.customQueryFunction({});

  }, []);
 
Let’s add filter so you can choose what data you want to receive rather than bother yourself with waiting for the whole data model to return - which can be a very long time.
useEffect(async () => {

    onUpdate(appID, dataUpdate);

    registerHooks(appID, [DataConnector]);

    const d = new Date();
    const dd = d.setDate(d.getDate() - 14);
    const dateStr = new Date(dd).toISOString().split("T")[0];

    const filter = {
      ["s3::date"]: {
        [Op.gte]: dateStr,
      },
    };

    const result = await API[appID].DataConnector.customQueryFunction({
      filter: filter,
      fields: "day_start,class_5min",
    });
    
  }, []);
You can se constant d called as a constructor, returns a new Date object.
It’s implemented further in dd to get a date value of -14 which will get you a starting date from 14 days ago. This is how you will get a period of recent 14 days of data - it will look something like this: 1640875396784
Now we use dateStr to convert that value to string, so the final product is 2021-12-30.
 
To be able to go to next step in filtering we’ll need to also enable data query Operator by importing it from “@prifina/hooks”
import { usePrifina, Op } from "@prifina/hooks";
Once we do we implement it in filter with the help of SQL syntax expression, we get all the date values greater than or equal to ( gte ) from dateStr starting point.
 const filter = {
      ["s3::date"]: {
        [Op.gte]: dateStr,
      },
    };
In final step after we have filtered a period of data we need to process it - we’ll do that with the help of processData() function.
 
 
If there are multiple data connectors used or one data connector with different query functions just repeat the same process every time and place them inside separate processData() functions. You can use the sam useEffect hook to pass the data to them.
 
Final look:

const [finalData, setFinalData] = useState("");

const processData = (data) => {
//receiving passed data
const processedData = ...
//processing the data further to get desired data object

//useState hook can help with declaring the final product 
setFinalData(processedData);
}


useEffect(async () => {
    // init callback function for background updates/notifications
    onUpdate(appID, dataUpdate);
    // register datasource modules
    registerHooks(appID, [Oura]);

    const d = new Date();

    const dd = d.setDate(d.getDate() - 14);
    const dateStr = new Date(dd).toISOString().split("T")[0];

    console.log(dateStr, "sda");

    const filter = {
      ["s3::date"]: {
        [Op.gte]: dateStr,
      },
    };

    const activityResult = await API[appID].Oura.queryActivitySummariesAsync({
      filter: filter,
      fields: "day_start,class_5min",
    });

//adding processData function passing the activityResult object 
    if (stage === "dev") {
      processData(activityResult.data.getDataObject.content[1]);
    }
  }, []);

dataUpdate

Async function used to update the widgets properties and enable control and interaction of the same - mainly used in widget settings. Declared using onUpdate in useEffect hook alongside appID
let defaultCity = city;
  if (
    typeof data !== "undefined" &&
    data.hasOwnProperty("settings") &&
    typeof data.settings === "object" &&
    data.settings.hasOwnProperty("city") &&
    data.settings.city.length > 0
  ) {
    defaultCity = data.settings.city;
  }

  const [searchCity, setCity] = useState(defaultCity);

  const dataUpdate = async (payload) => {
    if (
      payload.hasOwnProperty("settings") &&
      typeof data.settings === "object" &&
      payload.settings.hasOwnProperty("city")
    ) {
      setCity(payload.settings.city);
      setUrl(
        `${API_BASE_URL}/data/2.5/onecall?q=${data.settings.city}&units=metric&appid=${API_KEY}`
      );
    }

    if (
      payload.hasOwnProperty("data") &&
      payload.data.hasOwnProperty("content")
    ) {
      // process async data
      if (
        payload.data.dataconnector === "Oura/queryActivitySummariesAsync" &&
        payload.data.content.length > 1
      ) {
        processData(payload.data.content);
      }
    }
  };
 

Discover more about Symbol Operators used in filtering:

 
Operators and SequelizeOperators and Sequelize