{"id":34985280,"url":"https://github.com/o2web/react-core","last_synced_at":"2026-05-23T19:34:21.884Z","repository":{"id":40749767,"uuid":"144751111","full_name":"o2web/react-core","owner":"o2web","description":"O2 Web React Core","archived":false,"fork":false,"pushed_at":"2022-12-08T17:03:10.000Z","size":2173,"stargazers_count":0,"open_issues_count":38,"forks_count":1,"subscribers_count":4,"default_branch":"master","last_synced_at":"2023-02-28T02:16:28.113Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://www.o2web.ca/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/o2web.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-08-14T17:21:06.000Z","updated_at":"2020-02-24T14:20:27.000Z","dependencies_parsed_at":"2023-01-25T19:00:22.160Z","dependency_job_id":null,"html_url":"https://github.com/o2web/react-core","commit_stats":null,"previous_names":[],"tags_count":null,"template":null,"template_full_name":null,"purl":"pkg:github/o2web/react-core","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/o2web%2Freact-core","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/o2web%2Freact-core/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/o2web%2Freact-core/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/o2web%2Freact-core/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/o2web","download_url":"https://codeload.github.com/o2web/react-core/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/o2web%2Freact-core/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33410343,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-23T18:09:33.147Z","status":"ssl_error","status_checked_at":"2026-05-23T18:09:31.380Z","response_time":53,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-12-27T01:29:38.254Z","updated_at":"2026-05-23T19:34:21.878Z","avatar_url":"https://github.com/o2web.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# o2web-react-core\n\n[![NPM](https://img.shields.io/npm/v/o2web-react-core.svg)](https://www.npmjs.com/package/o2web-react-core)\n[![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)\n\n## Install\n\n```bash\nnpm install --save o2web-react-core\n```\n\n## Usage\n\n### Available components and methods\n\n```js\n// using ES6 modules\nimport {\n  BaseRoute,\n  CacheBuster,\n  CrumbRoute,\n  LanguageSwitcher,\n  GAListener,\n  NavLink,\n  Redirector,\n  Route,\n  translateRoute,\n  ValidateRoutes,\n} from 'o2web-react-core';\n```\n\nExample in `/example`\n\n### GraphQL Requests\n\nThis package uses [Apollo Client](https://github.com/apollographql/apollo-client) as GraphQL client.\n\nDuplicate `.env.sample` file and add GraphQL endpoint\n\n```bash\nREACT_APP_API_URL=https://example.com/graphql\n```\n\nCheck `/example/src/app/actions/artworks` directory for GraphQL queries definition examples\n\n```js\nexport default {\n  fetchArtwork: `\n    query($id: ID!) {\n      artwork(id: $id) {\n        id\n        name\n        description\n      }\n    }\n  `,\n  fetchArtworks: `\n    query($limit: Int) {\n      artworks(limit: $limit) {\n        artworks {\n          id\n          name\n          description\n        }\n      }\n    }\n  `,\n};\n\n```\n\n### Authentication\n\nThis package is intended to authenticate with a GraphQL Authentication with JWT. You can use the gem [graphql-auth](https://github.com/o2web/graphql-auth) if you are using rails for your api\n\nThe authentication forms Components are located in `example/src/app/components/user\n\n### Redux\n\nThis package uses [Redux](https://github.com/reduxjs/redux) to manage data states\n\nCheck `/example/src/app/reducers` directory for reducers stucture\n\n```js\nimport { combineReducers } from 'redux';\nimport { i18nState } from 'redux-i18n';\nimport { reducer as formReducer } from 'redux-form';\nimport artworkReducer from './artwork';\nimport artworksReducer from './artworks';\n\nconst rootReducer = combineReducers({\n  i18nState,\n  form: formReducer,\n  artwork: artworkReducer,\n  artworks: artworksReducer,\n});\n\nexport default rootReducer;\n\n```\n\n[react-redux](https://github.com/reduxjs/react-redux) is use to connect Redux data state to React components\n\n```js\nimport { connect } from 'react-redux';\n\n...\n\nexport default connect(mapStateToProps, actions)(Artworks);\n```\n\nThis package also uses [redux-action-creator](https://github.com/andy-shea/redux-action-creator) to define Redux actions types\n\nCheck `/example/src/app/actions/artworks` directory for redux action types examples\n\n```js\nimport { async, createTypes } from 'redux-action-creator';\n\nexport default createTypes([\n  ...async('FETCH_ARTWORK'),\n  ...async('FETCH_ARTWORKS'),\n], 'ARTWORKS');\n```\n\nDefine the Redux Store this way `src/config/redux/store.js`\n\n```js\nimport reduxThunk from 'redux-thunk';\nimport { createStore, applyMiddleware } from 'redux';\nimport reducers from '../../app/reducers/index';\n\nconst middlewares = [reduxThunk];\n\nconst createStoreWithMiddleware = applyMiddleware(...middlewares)(createStore);\nconst store = createStoreWithMiddleware(reducers);\n\nexport default store;\n\n```\n\n### Translations\n\nThis package uses [redux-i18n](https://github.com/APSL/redux-i18n) for texts translation\n\nCheck `/example/src/app/components/pages/About.js` for translation examples\n\n```js\nfunction About(pros, { t }) {\n  return (\n    \u003cdiv\u003e\n      \u003ch2\u003e{t('pages.titles.about')}\u003c/h2\u003e\n    \u003c/div\u003e\n  );\n}\n\nAbout.contextTypes = {\n  t: PropTypes.func,\n};\n```\n\nCreate a directory with translations in `/example/src/config/locales` directory\n\n`t('pages.titles.about')` matches `/example/src/config/locales/en/pages.js` definition\n\n```js\nexport default {\n  titles: {\n    home: 'Home page',\n    about: 'About page',\n  },\n};\n```\n\nTranslation keys can be nested\n\n### Router\n\nThis package uses [react-router v4](https://github.com/ReactTraining/react-router) to define translated routes.\nThese routes must be named with their translations keys.\n\nCheck `/example/src/config/locales/en/routes.js` for routes definitions\n\n```js\nexport default {\n  en: 'en',\n  about: 'about',\n  artworks: 'artworks',\n  demo: 'demo-form',\n};\n\n```\n\n`\u003cBaseRoute /\u003e`, `\u003cLanguageSwitcher /\u003e`, `\u003cNavLink /\u003e`, `\u003cRoute /\u003e` can be used for translated routes\n\n### Breadcrumbs\n\nThis package uses [react-breadcrumbs](https://github.com/svenanders/react-breadcrumbs) to generate automatic breadcrumbs.\n\nRoutes must be nested so react-breadcrumbs can generate breadcrumbs.\nCheck `/example/src/app/components/layouts/PrimaryLayout.js` for automatic breadcrumbs definition examples\n\n```js\n\u003cmain\u003e\n  \u003cBreadcrumbs /\u003e\n  \u003cRoute exact path=\"/en\" component={HomePage} /\u003e\n  \u003cCrumbRoute exact path=\"/en/about\" title=\"about\" component={AboutPage} /\u003e\n  \u003cCrumbRoute\n    path=\"/en/artworks\"\n    title=\"artworks\"\n    render={({ match }) =\u003e\n      \u003cSwitch\u003e\n        \u003cRoute exact path={match.url} component={Artworks} /\u003e\n        \u003cCrumbRoute path={`${match.url}/:artworkId`} title=\"artwork\" component={Artwork} /\u003e\n      \u003c/Switch\u003e\n    }\n  /\u003e\n  \u003cCrumbRoute exact path=\"/en/demo\" title=\"demo\" component={DemoForm} /\u003e\n\u003c/main\u003e\n```\n\n`\u003cCrumbRoute /\u003e` can be used for translated routes\n\n### Redirects\n\nUpdate redirects array located at `/example/src/config/redirects/redirects.js`\n\n```js\nconst redirects = [\n  { from: '/en/route', to: '/en/redirect-to' },\n];\n```\n\n### SEO\n\nThis package uses [react-helmet](https://github.com/nfl/react-helmet) to manage document head\n\n`\u003cHelmet /\u003e` can be used in nested components. The most nested definition will be displayed in the page.\nCheck `/example/src/app/components/App.js` for document head definition example\n\n### Tag Manager\n\nAdd GTM ID in the .env file `REACT_APP_TAG_MANAGER_ID=GTM-000000`.\nUse `https://www.npmjs.com/package/react-gtm-module`.\n\n### Forms\n\nThis packages uses [redux-form](https://github.com/erikras/redux-form) for form definition\n\nCheck `/example/src/app/components/forms/Demo.js` for form example\n\n```js\nimport { Field, reduxForm } from 'redux-form';\nimport Input from './fields/input/Input';\n\n\u003cform onSubmit={submitForm} className=\"form--demo\"\u003e\n  \u003cField\n    name=\"firstName\"\n    component={Input}\n    type=\"text\"\n    placeholder=\"Your name...\"\n  /\u003e\n\n  ...\n\nexport default connect(mapStateToProps)(reduxForm({\n  form: 'demo',\n  enableReinitialize: true,\n  validate,\n}, mapStateToProps)(DemoForm));\n```\n\n### Cookies\n\nThis package uses [redux-cookie](https://github.com/reactivestack/cookies)\n\n`\u003cCookiesProvider /\u003e` is defined in `/example/src/app/components/App.js` so `cookies` prop is available to children components\n\n\n### CacheBuster\n\n\u003e [This article](https://dev.to/flexdinesh/cache-busting-a-react-app-22lk) was used to create the CacheBuster component.\n\nReact apps can sometimes get stuck on the client's side cache (ex: when the app is added to the phone's homepage). You can use the CacheBuster component to help refresh the app. Here are the steps to help you set it up.\n\n* Copy the `generate-build-version.js` script to your app folder\n* Add the `generate-build-version` task to your app's `package.json` and call it with the prestart/prebuild hook. This will generate a meta.json file in your `static` folder.\n\n```\n\"scripts\": {\n    \"generate-build-version\": \"node ./generate-build-version.js\",\n    \"prestart\": \"npm run generate-build-version\",\n    \"pressr:build\": \"npm run generate-build-version\",\n    \"prestatic:build\": \"npm run generate-build-version\"\n    [...]\n    \"static:build\": \"REACT_APP_CURRENT_APP_VERSION=$npm_package_version react-app-rewired build\", # hosted on Heroku\n    \"static:build\": \"react-app-rewired build\", # not hosted on Heroku\n    [...]\n},\n```\n* If your app is hosted on Heroku, you must add this `REACT_APP_CURRENT_APP_VERSION=$npm_package_version` to the build and start script in package.json to include the current version in your build.\n* If your app is not hosted on Heroku, you can simply add `REACT_APP_CURRENT_APP_VERSION=$npm_package_version` to your .env file.\n* In the root component of your App (generally `src/app/components/App.js`), add the CacheBuster component around your app code\n* The CacheBuster will now compare the current version, from your `.env` file, which should be cached, and the current build version, from the `generate-build-version.js`, which should not be cached, because we fetch it asynchronously and browsers don't cache XHR requests.\n\n\n\n## Advanced usage\n\n### Add custom Apollo client\n\nYou can add a custom Apollo client to further customize your app with advanced features. To do so, you need to create a custom client, import it in your action files and send it as a parameter to the async query object. You can find an example of this feature in the example folder (custom client in `example/src/config/graphql/client.js` and usage in `example/src/app/actions/artworks/index.js`).\n\n## Development\n\nStart package core\n\n```bash\ncd /\nnpm install\nnpm start\n```\n\nStart example app\n\n```bash\ncd /example\nnpm install\nnpm start\n```\n\nRun server build\n\nTo run the server build update `package.json` at the root of the project to point to the server build.\n\n```\n\"ssr:serve\": \"nodemon -r dotenv/config ./example/build/server.js\",\n```\n\n\n### Javascript Linting\n\nThis package uses [ESLint](https://github.com/eslint/eslint) with [Airbnb React/JSX Style Guide](https://github.com/airbnb/javascript/tree/master/react)\nas React/JSX style guide\n\n----------------------------------------\nPackage created with [create-react-library](https://github.com/transitive-bullshit/create-react-library)\n\n## License\n\nMIT © [o2web](https://github.com/o2web)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fo2web%2Freact-core","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fo2web%2Freact-core","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fo2web%2Freact-core/lists"}