# State Management

## Context API

We are using context for login methods - **`Auth0, JWT, Firebase.`**

{% tabs %}
{% tab title="Vite (TS)" %}
{% code title="src/contexts/configContext.tsx" %}

```javascript
import { createContext, ReactNode, useMemo } from 'react';

// project imports
import config from 'config';
import { useLocalStorage } from 'hooks/useLocalStorage';

// types
import { ConfigContextValue, ConfigStates } from 'types/config';

export type Props = {
  children: ReactNode;
};

// ==============================|| CONFIG CONTEXT ||============================== //

export const ConfigContext = createContext<ConfigContextValue | undefined>(undefined);

// ==============================|| CONFIG PROVIDER ||============================== //

export function ConfigProvider({ children }: Props) {
  const { state, setState, setField, resetState } = useLocalStorage<ConfigStates>('berry-config-vite-ts', config);

  const memoizedValue = useMemo(() => ({ state, setState, setField, resetState }), [state, setField, setState, resetState]);

  return <ConfigContext.Provider value={memoizedValue}>{children}</ConfigContext.Provider>;
}

```

{% endcode %}
{% endtab %}

{% tab title="Vite (JS)" %}
{% code title="src/contexts/configContext.jsx" %}

```javascript
'use client';
import PropTypes from 'prop-types';

import { createContext, useMemo } from 'react';

// project imports
import config from 'config';
import { useLocalStorage } from 'hooks/useLocalStorage';

// ==============================|| CONFIG CONTEXT ||============================== //

export const ConfigContext = createContext(undefined);

// ==============================|| CONFIG PROVIDER ||============================== //

export function ConfigProvider({ children }) {
  const { state, setState, setField, resetState } = useLocalStorage('berry-config-next-ts', config);

  const memoizedValue = useMemo(() => ({ state, setState, setField, resetState }), [state, setField, setState, resetState]);

  return <ConfigContext.Provider value={memoizedValue}>{children}</ConfigContext.Provider>;
}

ConfigProvider.propTypes = { children: PropTypes.node };

```

{% endcode %}
{% endtab %}

{% tab title="Next (TS)" %}
{% code title="src/contexts/configContext.tsx" %}

```typescript
'use client';

import { createContext, ReactNode, useMemo } from 'react';

// project imports
import config from 'config';
import { useLocalStorage } from 'hooks/useLocalStorage';

// types
import { ConfigContextValue, ConfigStates } from 'types/config';

export type Props = {
  children: ReactNode;
};

// ==============================|| CONFIG CONTEXT ||============================== //

export const ConfigContext = createContext<ConfigContextValue | undefined>(undefined);

// ==============================|| CONFIG PROVIDER ||============================== //

export function ConfigProvider({ children }: Props) {
  const { state, setState, setField, resetState } = useLocalStorage<ConfigStates>('berry-config-next-ts', config);

  const memoizedValue = useMemo(() => ({ state, setState, setField, resetState }), [state, setField, setState, resetState]);

  return <ConfigContext.Provider value={memoizedValue}>{children}</ConfigContext.Provider>;
}

```

{% endcode %}
{% endtab %}

{% tab title="Next (JS)" %}
{% code title="src/contexts/configContext.jsx" %}

```javascript
'use client';
import PropTypes from 'prop-types';

import { createContext, useMemo } from 'react';

// project imports
import config from 'config';
import { useLocalStorage } from 'hooks/useLocalStorage';

// ==============================|| CONFIG CONTEXT ||============================== //

export const ConfigContext = createContext(undefined);

// ==============================|| CONFIG PROVIDER ||============================== //

export function ConfigProvider({ children }) {
  const { state, setState, setField, resetState } = useLocalStorage('berry-config-next-ts', config);

  const memoizedValue = useMemo(() => ({ state, setState, setField, resetState }), [state, setField, setState, resetState]);

  return <ConfigContext.Provider value={memoizedValue}>{children}</ConfigContext.Provider>;
}

ConfigProvider.propTypes = { children: PropTypes.node };

```

{% endcode %}
{% endtab %}
{% endtabs %}

## State

```javascript
export const initialState = {
    isOpen: 'dashboard', //for active default menu
    navType: config.theme,
    locale: config.i18n,
    rtlLayout: false, // rtlLayout: config.rtlLayout,
    opened: true
};
```

## Designing Actions

We designed the state structure based on the app's requirements.

Based on that list of things that can happen, we created a list of actions that our application will use:

```javascript
export const LOGIN = 'LOGIN';
export const LOGOUT = 'LOGOUT';
export const REGISTER = 'REGISTER';
export const FIREBASE_STATE_CHANGED = 'FIREBASE_STATE_CHANGED';
```

## **Writing Reducers**

Creating the Root Reducer - A Redux app really only has one reducer function: the "root reducer" function

{% tabs %}
{% tab title="Vite (TS)" %}
{% code title="src/store/slices/contact.ts" %}

```javascript
...
// project imports
import axios from 'utils/axios';
import { dispatch } from '../index';
...

...
// Reducer
export default slice.reducer;
...

export function getContacts() {
    return async () => {
        try {
            const response = await axios.get('/api/contact/list');
            dispatch(slice.actions.getContactsSuccess(response.data.contacts));
        } catch (error) {
            dispatch(slice.actions.hasError(error));
        }
    };
}

export function modifyContact(contact: UserProfile) {
    return async () => {
        try {
            const response = await axios.post('/api/contact/modify', contact);
            dispatch(slice.actions.modifyContactSuccess(response.data));
        } catch (error) {
            dispatch(slice.actions.hasError(error));
        }
    };
}
```

{% endcode %}
{% endtab %}

{% tab title="Vite (JS)" %}
{% code title="src/store/slices/contact.js" %}

```typescript
...
// project imports
import axios from 'utils/axios';
import { dispatch } from '../index';
...

...
const slice = createSlice({
    name: 'contact',
    initialState,
    reducers: {
        // HAS ERROR
        hasError(state, action) {
            state.error = action.payload;
        },

        // GET CONTACTS
        getContactsSuccess(state, action) {
            state.contacts = action.payload;
        },

        // MODIFY CONTACT
        modifyContactSuccess(state, action) {
            state.contacts = action.payload;
        }
    }
});
...

export function getContacts() {
    return async () => {
        try {
            const response = await axios.get('/api/contact/list');
            dispatch(slice.actions.getContactsSuccess(response.data.contacts));
        } catch (error) {
            dispatch(slice.actions.hasError(error));
        }
    };
}

export function modifyContact(contact) {
    return async () => {
        try {
            const response = await axios.post('/api/contact/modify', contact);
            dispatch(slice.actions.modifyContactSuccess(response.data));
        } catch (error) {
            dispatch(slice.actions.hasError(error));
        }
    };
}
```

{% endcode %}
{% endtab %}

{% tab title="Next (TS)" %}
{% code title="src/store/slices/contact.ts" %}

```typescript
...    
// project imports
import axios from 'utils/axios';
import { dispatch } from '../index';
...

...
// Reducer
export default slice.reducer;
...

export function getContacts() {
    return async () => {
        try {
            const response = await axios.get('/api/contact/list');
            dispatch(slice.actions.getContactsSuccess(response.data.contacts));
        } catch (error) {
            dispatch(slice.actions.hasError(error));
        }
    };
}

export function modifyContact(contact: UserProfile) {
    return async () => {
        try {
            const response = await axios.post('/api/contact/modify', contact);
            dispatch(slice.actions.modifyContactSuccess(response.data));
        } catch (error) {
            dispatch(slice.actions.hasError(error));
        }
    };
}
```

{% endcode %}
{% endtab %}

{% tab title="Next (JS)" %}
{% code title="src/store/slices/contact.js" %}

```javascript
...
// project imports
import axios from 'utils/axios';
import { dispatch } from '../index';
...

...
const slice = createSlice({
    name: 'contact',
    initialState,
    reducers: {
        // HAS ERROR
        hasError(state, action) {
            state.error = action.payload;
        },

        // GET CONTACTS
        getContactsSuccess(state, action) {
            state.contacts = action.payload;
        },

        // MODIFY CONTACT
        modifyContactSuccess(state, action) {
            state.contacts = action.payload;
        }
    }
});
...

export function getContacts() {
    return async () => {
        try {
            const response = await axios.get('/api/contact/list');
            dispatch(slice.actions.getContactsSuccess(response.data.contacts));
        } catch (error) {
            dispatch(slice.actions.hasError(error));
        }
    };
}

export function modifyContact(contact) {
    return async () => {
        try {
            const response = await axios.post('/api/contact/modify', contact);
            dispatch(slice.actions.modifyContactSuccess(response.data));
        } catch (error) {
            dispatch(slice.actions.hasError(error));
        }
    };
}
```

{% endcode %}
{% endtab %}
{% endtabs %}
