0.9.25 • Published 2 years ago

frupal v0.9.25

Weekly downloads
-
License
ISC
Repository
github
Last release
2 years ago

Frupal, a Drupal React JS library

(Update: Pager UI v23+ now injects 'page=1' into the url; which now supports proper pagination. Nested pagination temporarily not support else such nested pager must be set to 'constant' type. You can keep using v22 if you need nested pagination.)

A Drupal library to make decoupled Drupal easier to manage/build from the frontend by implementing common communication channels to the backend.

All modules/functions/features may be imported from 'frupal/modules'

(This ReadMe is still a little scattered at the moment; sorry!!!)

Quite a few functions will be implemented over time.... and my list for now may include many, all or more of the following:

A login function

Json function to call the all json endpoints.

A Rest function, an alternative to Json function where a rest endpoint is needed.

Search function.

Contact form submit function.

Flagging function.

User registration function.

Password reset function.

A Pager UI

Except for the UI components (components are often referred to as module, in staying true to Drupal definations), all functions will be designed to return an object response which will include the default Json response for the endpoint and additional details like logs or status message/code where necessary.

Frupal is will be available on npm soon after I start pushing to this repository.

Important Notice:

To use the authenticated (logged in user specific processes) specific context and functions of this library, the aspect of your app that required authentication must be wrapped in the Authorisation module, else it won't work as expected. If your whole App is dependednt on the drupal and required authenticated user access, it's a good idea to put your App.js file inside the Authorisation module of the library. Like This: <Authorization app={<App />} /> This allows 'profile' context among others to be available for use by simply importing React context API. Maybe I'll attach an issue or page to show this feature at work soon.

How to Use

Create a config file, as frupal.config.js, in the root of your react app and set your basic remote configurations as stated below:

export const frupal = {
remote: {
uri: "http://backendWebsiteUri.com",
jsonapi: "yourJsonApiEndpoint", //default is jsonapi
restapi: "restapi",
subrequests: true,
entityRouter: true,
},
authenticationMethod: "access_token",
saveTokenToLocalStorage: true,
};

While must of the options are optional, it is important to export your Minimum default config as:

export const frupal = {
remote: {
uri: "http://backendWebsiteUri.com",
}
};

Backend URI is the minimum allowed to use the library in your project.

When only your backend uri is set, it is assumed that all Json Api call is drupal default of 'jsonapi'. That is: http://backendWebsiteUri.com/jsonapi If the Json Api point has however been changed manually or using drupal modules like 'Json Default Extras' module, please specify your new Json Api endpoint as below:

export const frupal = {
remote: {
uri: "http://backendWebsiteUri.com",
jsonapi: "newJsonEndpoint",
restapi: "restapi",
subrequests: true,
entityRouter: true,
},
authenticationMethod: "access_token",
saveTokenToLocalStorage: true,
};

A default endpoint is set for rest call @ restapi; that is: http://backendWebsiteUri.com/restapi You can change this as well like you changed jsonapi.

Extras:

Your preferred authentication method may be specified here. This will be used to process access control for authenticated users. If none is specified, all access restricted api call will be done with access_token. Only access_token is implemented for now though. You will probably need to install a drupal module to export access_token on the login response to take advantage of this feature. The drupal 'getjwtonlogin' module is a good bet if you use JWT module for authentication.

set saveTokenToLocalStorage = true for an optional process to save your access_token to the browser Local Storage. It is saved as sessionToken and can easily be retrieved with localStorage.getItem("sessionToken"). An option to save this in sessionStorage may be implement later. If you wish to save another kind of token rather than access_token, set your default authenticationMethod in frupal.config.js and this token key|value pair will be saved to localStorage. sessionToken is JSON stringified JSON.stringify(). Note: it is a good idea to save your sessionToken so <Authorization /> can always fetch from there to keep track of returning signed in users.

if you are using 'Entity Router' Module for routing uri and subrequests Module for simultaneous multiple requests, then set either or both as true. Entity Router feature is disabled by default however the Subrequest module feature is yet to be implemented. Pardon me.

Default Drupal profile fields (User entity fields) will be returned with your response if you are using the Login() function (see below sections) and can be imported to your App with the profile context by...

import Profile from "frupal/Authorization"; and providing context const { profile } = useContext(Profile);

Custom profile properties can be optionally inserted by doing setProfile(...profile, user_badge:'Colonel') and swapping the context above with the one below. const { profile, setProfile } = useContext(Profile);

If you which to automatically include custom profile field to your app however, include such fields in the config file as below:

profile_fields: "field_first_name", "field_last_name", "field_phone_nos"

Please follow this pattern for this to work

  1. Only drupal machine names are valid.
  2. Referenced fields should be preceeded with a square bracket containing 'relation' in front. relationfield_tags //Note: yet to be implemented.

Your complete config file may look like the below:

export const frupal = {
remote: {
uri: "http://backendWebsiteUri.com",
jsonapi: "jsonapi",
restapi: "restapi",
subrequests: true,
entityRouter: true,
},
profile_fields: ["field_fname", "field_lname", "field_phone_nos", [relation]field_tags],
authenticationMethod: "csrf_token", //if using drupal csrf_token
saveTokenToLocalStorage: true,
};

For development purpose, you may consider the below config to create a dynamic configuration that environment specific configuration between local development and remote deployment.

const prod = {
   remote: {
      uri: "https://mellywood.com",
      jsonapi: "jsonapi",
      restapi: "restapi",
      subrequests: true,
      entityRouter: true,
   },
   profile_fields: [
   "field_fname",
   "field_lname",
   "field_phone_nos",
   "[relation]field_tags]",
   ],
};
const dev = {
   remote: {
      uri: "http://mellywood.local",
      jsonapi: "jsonapi",
      restapi: "restapi",
      subrequests: true,
      entityRouter: true,
   },
   profile_fields: [
   "field_fname",
   "field_lname",
   "field_phone_nos",
   "[relation]field_tags]",
   ],
};
export const frupal = process.env.NODE_ENV === "development" ? dev : prod;

Note:

Unless the 'Token' module is called and set, you will have no access to the functionality of the Profile context.

The Login() Function.

Please note that there's no way to check if a user is already logged in. You have to create a logic to handle that check yourself.

5 variables may be provided for the Login function as named below: username, mail, password, loginType, action.

At least one of username or mail (email) is needed with password to process signing in a user. When the email option is enabled, you'll have to explicitly set it using loginType= 'email' for it to be enabled. You most likely need the 'Rest Email Login' drupal module for this to work, as the endpoint is used to communicate with the backend. That is: mysite.com/user/email-login?_format=json

Last but not the least, if you intend to execute a function if login is successful, or at any other statusCode response; please place your function in the 'action' property as an object with the key|values as action: { statusCode: 200, func: processLoggedInAction }. statusCode may be ignored if you only want to execute the function on successful logged In at code 200. Full Login function sample should look like below:

Login({
username: "myName", //optional if loginType is set to email
mail: "myEmail@gmail.com", //optional. Must be provided if loginType is set to email
password: "myPassword.",
loginType: 'email', //optional
saveTokenToLocalStorage: true, //optional
action: {
statusCode: 200, //optional, defaults to 200
func: loggedInAction //you can import a callback function to be processed at a specific code response of your choice.
} //optional
}).then((response) => {
console.log(response); //process whatever you want to do with the response.
});

Login response is returned as an object

{
json: "returned jsonapi response",
log: "Any accompanying logging/message/notice/error",
statusCode: "200", //server response status code,
token: {}, //preferred logged in token with key and type. //only available if authenticationMethod is set in frupal.config.js
}

Site-wide token may be optionly set from Login() response by calling useContext and re-exporting response to token as follow:

const { setToken } = useContext(Token);
setToken(response.token) // if authenticationMethod is set in frupal.config.js, otherwise use the approach below.
setToken({
type: "access_token", //if you're using access_token or provide any other you are using
key: response.json.access_token,
});

All available token can be seen in the response.json of the returned response.

The Json() Function

By default Json() functions accepts an endpoint variable to fetch your async json call, or an object, or an array of objects for simultaneous asyncronous calls to endpoint(s). All object must have an endpoint key to work. Your object variable should be in the below format:

{
endpoint: "node/article", //required
headers: {
"Content-Type": "application/vnd.api+json",
Accept: "application/vnd.api+json",
},
body: {},
method: "get",
};

Every key is optional except the endpoint, and are just available if you desire to make custom modifications. You will likely need the body option if you are making a POST, PATCH or DELETE requests. Simultaneous or multiple asyc request should be in objects in arrays: Json( {endpoint: 'node/article', id: "req9", waitFor: "", }, {endpoint: 'node/page',id: "req9", waitFor: "",} ) All request will be returned as one. Use 'id' to identify each request; if unspecified, the response will be assigned serially. Note: The 'waitFor' will be used to implement dependent async calls but this feature is yet to be implemented. Use: Json().then((response) => console.log(response)) to return your expected results when you need the data response.

The Rest() Function

The Rest Function only accepts a string endpoint as variable.

The ER() Function.

Using Drupal Entity Router module. Like Rest(), ER() Function only accepts a string endpoint as variable; this would be the url, or pathauto (if enabled) url, of the entity.

The SR() Function

Yet to be implemented.

The Contact() Function

Drupal default contact module must be enabled on your drupal website to use this function. If there's no custom modification and you're just using the default feedback form, then only provide object like the one below in your function.

{
form: "site_feedback_form",// optional. you only need to specify a form if you're using a form diferent from drupal default feedback form.
name: "person submitting the form", //optional and will default to 'Guest'
mail: "email of user submitting the form", //required
subject: "subject of message", //optional and default to 'General'
message: "message body", //required
profile: profile, //if you use the profile context feature, then you can use it here for autheticated users, and mail and name above will be ingored in favour of the profile info.
};

Pager UI

At the barest minimum, the url is required. You will also need the pageContents function to import your remote data. Saving the importd pageContent in a state is a good idea.

<Pager url={url} pageContents={(pageContent) => setPagerData(pageContent)} />

Pager types are similar to Drupal Views' approach and options are:

  1. mini; equavalent to mini-pager in views
  2. more; Simple adds the next lsit to the bottom of current items.
  3. infinite; extra type to allow infinite loading. Pagination count may be optionally specified. Note: yet to be implemented.
  4. constant; Print a one time specified list. Since JsonApi pagination is an async call, full pager similar to Drupal Views isn't implemented at the moment for efficiency reason on my part. Default is always mini when none, or an unknown type is specified.

Full pager options is illustrated below:

<Pager
   url={dataUrl}
   enablePageOne={true} //By default, 'page=1' is ignored. Set as true to allow injecting '?page=1' into url
   pageContents={(pageContent) => setPagerData(pageContent)}
   type="mini" //options include mini/more/constant
   authentication={false} //Boolean. only available if using the authentication module
   pagination={10} // nodes or entity per page
   buttonClass="text-color-green bg-blue" //classes for next and previous buttons
   previousButton={<FaArrowAltCircleLeft />} //Previous button. Can be string or JSX element. Defaults to '<'
   nextButton={<FaArrowAltCircleRight />} //Next button. Can be string or JSX element. Defaults to '>'
   className="mt-5 flex gap-3 w-fit mx-auto items-center" //classes for the pager itself.
/>
0.9.25

2 years ago

0.9.24

2 years ago

0.9.23

2 years ago

0.9.21

2 years ago

0.9.22

2 years ago

0.9.20

2 years ago

0.9.2

2 years ago

0.9.1

2 years ago