> For the complete documentation index, see [llms.txt](https://trixtateam.gitbook.io/trixta-js-rjsf/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://trixtateam.gitbook.io/trixta-js-rjsf/quickstart.md).

# Quickstart

### Setup CRA Template

```
yarn create react-app --template cra-template-rb my-example-app
cd my-example-app
```

### Install trixta-js packages

```
yarn add @trixtateam/trixta-js-core @trixtateam/trixta-js-rjsf @trixtateam/phoenix-to-redux @rjsf/core @rjsf/utils @rjsf/validator-ajv6
```

<details>

<summary>Generate Login Page Example</summary>

```
yarn generate
```

Follow the prompt instructions and create component under Pages directory

Replace file contents with below code. `src\app\pages\LoginPage`

```tsx
/**
 *
 * LoginPage
 *
 */
import {
  ReservedTrixtaRoles
} from '@trixtateam/trixta-js-core';
import {
  TrixtaActionComponent,
  TrixtaLoginWidget,
  TrixtaReactionComponent,
} from '@trixtateam/trixta-js-rjsf';
import { PageWrapper } from '../../components/PageWrapper';

interface Props {}

export function LoginPage(props: Props) {
  return (
    <PageWrapper>
    <div
        style={{
          margin: '10px',
          padding: '10px',
          backgroundColor: '#dce6ea',
        }}
      >
        <TrixtaLoginWidget />
      </div>
      <div
        style={{
          margin: '10px',
          padding: '10px',
        }}
      >
        <TrixtaActionComponent
          actionName="example"
          roleName={ReservedTrixtaRoles.EVERYONE_AUTHED}
        />
      </div>
      <div
        style={{
          margin: '10px',
          padding: '10px',
        }}
      >
        <TrixtaReactionComponent
          reactionName="welcome"
          requestForEffect
          roleName={ReservedTrixtaRoles.EVERYONE_AUTHED}
        />
      </div>
    </PageWrapper>
  );
}
```

</details>

<details>

<summary>Setup Reducer</summary>

Replace file contents with below code.

`src\store\reducers.ts`

```typescript
/**
 * Combine all reducers in this file and export the combined reducers.
 */

import { combineReducers } from '@reduxjs/toolkit';
import { phoenixReducer } from '@trixtateam/phoenix-to-redux';
import { trixtaReducer } from '@trixtateam/trixta-js-core';
import { InjectedReducersType } from 'utils/types/injector-typings';

/**
 * Merges the main reducer with the router state and dynamically injected reducers
 */
export function createReducer(injectedReducers: InjectedReducersType = {}) {
  // Initially we don't have any injectedReducers, so returning identity function to avoid the error
  if (Object.keys(injectedReducers).length === 0) {
    return state => state;
  } else {
    return combineReducers({
      trixta: trixtaReducer,
      phoenix: phoenixReducer,
      ...injectedReducers,
    });
  }
}
```

</details>

<details>

<summary>Setup Trixta Saga</summary>

Create and copy saga file `src\app\sagas\app.ts`

```typescript
import { setupTrixtaSaga } from '@trixtateam/trixta-js-core';
import { fork } from 'redux-saga/effects';

export default function* rootSaga() {
  yield fork(setupTrixtaSaga);
}
```

</details>

<details>

<summary>Configure Store</summary>

Replace file contents with below code.

`src\store\configureStore.ts`

```typescript
import {
  configureStore,
  getDefaultMiddleware,
  StoreEnhancer,
} from '@reduxjs/toolkit';
import { createInjectorsEnhancer } from 'redux-injectors';

import { createPhoenixChannelMiddleware } from '@trixtateam/phoenix-to-redux';
import createSagaMiddleware from 'redux-saga';
import { createReducer } from './reducers';

export function configureAppStore() {
  const reduxSagaMonitorOptions = {};
  // Makes redux connected to phoenix channels
  const phoenixChannelMiddleWare = createPhoenixChannelMiddleware();
  const sagaMiddleware = createSagaMiddleware(reduxSagaMonitorOptions);
  const { run: runSaga } = sagaMiddleware;

  // Create the store with saga middleware
  const middlewares = [sagaMiddleware, phoenixChannelMiddleWare];

  const enhancers = [
    createInjectorsEnhancer({
      createReducer,
      runSaga,
    }),
  ] as StoreEnhancer[];

  const store = configureStore({
    reducer: createReducer(),
    middleware: [
      ...getDefaultMiddleware({
        thunk: false,
        immutableCheck: {
          ignore: ['socket', 'channel', 'trixta', 'phoenix', 'router'],
        },
        serializableCheck: false,
      }),
      ...middlewares,
    ],
    devTools:
      /* istanbul ignore next line */
      process.env.NODE_ENV !== 'production' ||
      process.env.PUBLIC_URL.length > 0,
    enhancers,
  });

  return store;
}
```

</details>

<details>

<summary>Connect Trixta</summary>

Replace file contents with below code.

`src\app\index.tsx`

```tsx
/**
 *
 * App
 *
 * This component is the skeleton around the actual pages, and should only
 * contain code that should be seen on all pages. (e.g. navigation bar)
 */

import { Helmet } from 'react-helmet-async';
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import { GlobalStyle } from '../styles/global-styles';
import { useTrixtaSpace } from '@trixtateam/trixta-js-core';
import { useTranslation } from 'react-i18next';
import { SagaInjectionModes, useInjectSaga } from 'redux-injectors';
import { HomePage } from './pages/HomePage/Loadable';
import { LoginPage } from './pages/LoginPage';
import { NotFoundPage } from './pages/NotFoundPage/Loadable';
import saga from './sagas/app';
export function App() {
  useInjectSaga({ key: 'App', saga, mode: SagaInjectionModes.DAEMON });
  useTrixtaSpace({ space: 'trixta-demo.space.trixta.io', params: {} });
  const { i18n } = useTranslation();
  return (
    <BrowserRouter>
      <Helmet
        titleTemplate="%s - React Boilerplate"
        defaultTitle="React Boilerplate"
        htmlAttributes={{ lang: i18n.language }}
      >
        <meta name="description" content="A React Boilerplate application" />
      </Helmet>

      <Routes>
        <Route path={process.env.PUBLIC_URL + '/'} element={<HomePage />} />
        <Route
          path={process.env.PUBLIC_URL + '/login'}
          element={<LoginPage />}
        />
        <Route element={<NotFoundPage />} />
      </Routes>
      <GlobalStyle />
    </BrowserRouter>
  );
}
```

</details>

### Run Example

```
yarn start
```

* Select the light theme
* Navigate to <http://localhost:3000/login>
* Follow the prompts and see what happens.
