cda-redux

cda-redux

Redux/RTK Query React SPA combining a user area (login/register/home) and a Star Wars module (listing, pagination, filtering) with authentication and session handling. The project demonstrates RTK Query for external API consumption and client-side cache management.

🎯 Context and goals

  • Structure a modern frontend application around Redux Toolkit and asynchronous API flows.
  • Implement an authentication baseline with token storage, current-user retrieval, and access protection.
  • Deliver browsing/search features with derived state and pagination.

πŸ› οΈ Deliverables

🧩 Design

{
  "scripts": {
    "dev": "vite ./",
    "build": "vite build ./",
    "serve": "vite preview ./"
  },
  "dependencies": {
    "@reduxjs/toolkit": "^1.6.2",
    "react": "^17.0.0",
    "react-redux": "^7.2.6",
    "react-router-dom": "^6.0.2",
    "redux": "^4.1.2",
    "redux-logger": "^3.0.6",
    "redux-persist": "^6.0.0"
  },
  "devDependencies": {
    "@vitejs/plugin-react": "^1.0.0",
    "vite": "^2.6.4"
  }
}
export const store = configureStore({
  reducer: {
    [peopleApi.reducerPath]: peopleApi.reducer,
    [authApi.reducerPath]: authApi.reducer,
    [usersManagerApi.reducerPath]: usersManagerApi.reducer,
    auth,
  },
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware().concat(
      usersManagerApi.middleware,
      authApi.middleware,
      peopleApi.middleware,
      logger
    ),
});

πŸ’» Development

const baseQuery = fetchBaseQuery({
  baseUrl: "<REDACTED_URL>",
  prepareHeaders: (headers, { getState }) => {
    const accessToken = getState().auth.accessToken;
    const xsrfToken = getState().auth.xsrfToken;

    if (accessToken && xsrfToken) {
      headers.set("authorization", `Bearer ${accessToken}`);
      headers.set("x-xsrf-token", xsrfToken);
    }

    return headers;
  },
});

The RTK Query layer encapsulates authentication/session endpoints (/auth/login, /auth/me, /auth/token, /users/). Source: cda-redux/vite-project/src/js/services/authService.js

export const authApi = createApi({
  reducerPath: "authApi",
  baseQuery: baseQuery,
  keepUnusedDataFor: false,
  endpoints: (builder) => ({
    login: builder.mutation({ query: (userInfo) => loginRequest("/auth/login", userInfo) }),
    fetchCurrentUser: builder.query({ query: () => authMeRequest("/auth/me") }),
    authToken: builder.mutation({ query: (emailToken) => authTokenRequest("/auth/token", emailToken) }),
    register: builder.mutation({
      query: (body) => ({ url: "/users/", method: "POST", body }),
    }),
  }),
});
<Routes>
  <Route path="/register" element={<Register />} />
  <Route path="/login" element={<Login />} />
  <Route path="/" element={<Navigate replace to="/home" />} />
  <Route path="/home" element={<HomePage />}>
    <Route path="users" element={<ListUsers />}></Route>
    <Route path="research-user" element={<p>Rechercher des utilisateurs</p>}></Route>
    <Route path="profil" element={<InfoProfil />}></Route>
  </Route>
  <Route path="/starwars/people" element={<PeopleStarWars />} />
  <Route path="/starwars/people/:peopleId" element={<PeopleStarWarsDetails />} />
</Routes>

The useIsAuth hook restores credentials from local storage, syncs Redux state, and triggers current-user fetch. Source: cda-redux/vite-project/src/js/hooks/useIsAuth.js

useEffect(() => {
  const accessToken = getLocalStorageItem("accessToken");
  const xsrfToken = getLocalStorageItem("xsrfToken");

  if (accessToken && xsrfToken) {
    dispatch(setCredentials({ accessToken, xsrfToken }));
  } else {
    dispatch(setIsInitialized());
  }

  const refreshToken = getLocalStorageItem("refreshToken");
  const email = getLocalStorageItem("email");
  if (email && refreshToken) {
    async () => {
      const result = authToken({ email, refreshToken });
      console.log("result auth/token", result);
    };
  }
}, []);

The Star Wars page implements text search, gender filtering, and pagination on top of SWAPI through RTK Query. Source: cda-redux/vite-project/src/js/pages/PeopleStarWars.jsx

const [page, setPage] = useState(1);
const { data: peopleStarwars, isFetching } = useFetchAllPeopleQuery(page);
const [searchTerm, setSearchTerm] = useState("");
const [activeCategory, setActiveCategory] = useState("");

<ul className="people-list">
  {peopleStarwars?.results
    ?.filter((val) => {
      if (searchTerm == "") return val;
      if (val.name.toLowerCase().includes(searchTerm.toLowerCase())) return val;
    })
    .map(({ name, height, mass, gender }, index) =>
      !activeCategory || activeCategory === gender ? (
        <div key={name}><PeopleItem index={index} name={name} height={height} mass={mass} gender={gender} /></div>
      ) : null
    )}
</ul>

πŸ—οΈ DevOps & Quality

  • The repository includes a GitLab CI pipeline for frontend build and dist artifact publication, followed by automated deployment stage. Source: cda-redux/.gitlab-ci.yml
image: node:16

stages:
  - build
  - deploy

build_parcel_master:
  stage: build
  script:
    - cd ./vite-project/
    - npm install
    - npm run build
  artifacts:
    expire_in: 20 mins
    paths:
      - ./vite-project/dist

πŸ“ˆ Results

  • Based on the analyzed Git history, the work spans 2021-11-08 -> 2026-02-14, with 24 commits across 3 contributors. The project delivers a structured SPA with API authentication, Redux-based token/session handling, and list/search navigation modules on external data. RTK Query usage standardizes asynchronous data flows and reduces network-call boilerplate. The technical benefit is a maintainable frontend foundation for multi-API use cases with centralized global state.

πŸ”§ Technical environment

  • Frontend: React 17, React Router 6, Vite.
  • State/API: Redux Toolkit, RTK Query (authApi, peopleApi, usersManagerApi), React Redux, Redux Logger.
  • Data sources: user/auth API (redacted URL), SWAPI (people).
  • Session: local token persistence + initialization through useIsAuth.
  • DevOps: GitLab CI (build, artifacts, deployment).
🌐 View the project

Tech Stack

Frontend
JavaScript
React
Redux
Vite