@@ -151,205 +151,222 @@ export const logout = async (): Promise<boolean> => {
151151
152152## Redirect to login page
153153
154- - Now, we will implement a redirect to login page on ` 401 ` Not Authorize responses:
154+ Now, we will implement a redirect to login page on ` 401 ` Not Authorize responses:
155155
156- _ ./front/src/common-app/auth/auth .hooks.ts_
156+ _ ./front/src/core/api/api .hooks.ts_
157157
158158``` javascript
159- import { useNavigate } from ' react-router-dom' ;
160- import { useSnackbarContext } from ' common/components' ;
161- import { linkRoutes } from ' core/router' ;
162- import { AxiosError } from ' axios' ;
159+ import React from " react" ;
160+ import axios , { AxiosError } from " axios" ;
161+ import { useNavigate } from " react-router-dom" ;
162+ import { useSnackbarContext } from " #common/components" ;
163+ import { linkRoutes } from " #core/router" ;
163164
164- type Request = (... params : any []) => Promise < any> ;
165-
166- export const useAuthRequest = < T extends Request[]> (... requestList: T ): T => {
165+ export const useApiConfig = () => {
167166 const navigate = useNavigate ();
168167 const { showMessage } = useSnackbarContext ();
169168
170- const authRequestList = requestList . map (( request ) => async ( ... params ) => {
171- try {
172- return await request ( ... params);
173- } catch (errorResponse) {
174- if (isAuthError (errorResponse) ) {
175- navigate ( linkRoutes . login );
176- showMessage ( ' You should login' , ' error ' );
177- throw undefined ;
169+ React . useEffect (( ) => {
170+ axios . interceptors . response . use (
171+ ( response ) => response,
172+ ( error : AxiosError ) => {
173+ if (error . response . status === 401 ) {
174+ showMessage ( " You should login" , " error " );
175+ navigate ( linkRoutes . login );
176+ }
178177 }
179- throw errorResponse;
180- }
181- }) as T ;
182-
183- return authRequestList;
184- };
185-
186- const isAuthError = (error: AxiosError): boolean => {
187- const errorCode = error .response .status ;
188-
189- return errorCode === 401 ;
178+ );
179+ }, []);
190180};
191-
192181```
193182
194- - Update barrel file:
183+ Update barrel file:
195184
196- _ ./front/src/common-app/auth /index.ts_
185+ _ ./front/src/core/api /index.ts_
197186
198187``` diff
199- export * from './auth.context ';
200- export * from './auth.vm ';
201- + export * from './auth .hooks';
188+ export * from './api.helpers ';
189+ export * from './api.constants ';
190+ + export * from './api .hooks';
202191
203192```
204193
205- - Use it on ` list container ` :
194+ Use it on ` router.component ` :
206195
207- _ ./front/src/pods/list/list.container .tsx_
196+ _ ./front/src/core/router/router.component .tsx_
208197
209198``` diff
210199import React from 'react';
211- + import { useAuthRequest } from 'common-app/auth';
212- import * as api from './api';
213- ...
214-
215- export const ListContainer: React.FunctionComponent<Props> = (props) => {
216- const { className } = props;
217- + const [getClientList, getOrderList] = useAuthRequest(
218- + api.getClientList,
219- + api.getOrderList
220- + );
200+ import { HashRouter, Routes, Route, Navigate } from 'react-router-dom';
201+ + import { useApiConfig } from '#core/api';
202+ import { LoginScene, ListScene } from '#scenes';
203+ import { switchRoutes } from './routes';
221204
222205...
223- const handleLoadClientList = async () => {
224- try {
225- - const apiClientList = await api.getClientList();
226- + const apiClientList = await getClientList();
227- const vmClientList = mapItemListFromApiToVm(apiClientList);
228- setClientList(vmClientList);
229- } catch {
230- setClientList(createNoTokenItemList());
231- }
232- };
233206
234- const handleLoadOrderList = async () => {
235- try {
236- - const apiOrderList = await api.getOrderList();
237- + const apiOrderList = await getOrderList();
238- const vmOrderList = mapItemListFromApiToVm(apiOrderList);
239- setOrderList(vmOrderList);
240- } catch {
241- setOrderList(createNoTokenItemList());
242- }
243- };
207+ const AppRoutes: React.FC = () => {
208+ + useApiConfig();
209+ return (
210+ <Routes>
211+ <Route path={switchRoutes.login} element={<LoginScene />} />
212+ <Route path={switchRoutes.list} element={<ListScene />} />
213+ <Route
214+ path={switchRoutes.root}
215+ element={<Navigate to={switchRoutes.login} />}
216+ />
217+ </Routes>
218+ );
219+ };
244220
245- ...
246221```
247222
248- - Use it on ` logout ` :
223+ > Try to fetch clients or orders without login.
249224
250- _ ./front/src/common-app/app-bar/app-bar.component.tsx_
225+ Create ` AuthRoute ` :
226+
227+ _ ./front/src/core/router/router.component.tsx_
251228
252229``` diff
253- ...
254- - import { AuthContext, createEmptyUserSession } from '../auth';
255- + import { AuthContext, createEmptyUserSession, useAuthRequest } from '../auth';
256- import * as api from './api';
257- import * as classes from './app-bar.styles';
258-
259- export const AppBarComponent: React.FunctionComponent = () => {
260- const { userSession, onChangeUserSession } = React.useContext(AuthContext);
261- const history = useHistory();
262- + const [logout] = useAuthRequest(api.logout);
263-
264- const handleLogout = async () => {
265- - await api.logout();
266- + await logout();
267- onChangeUserSession(createEmptyUserSession());
268- history.goBack();
269- };
230+ import React from 'react';
231+ import {
232+ HashRouter,
233+ Routes,
234+ Route,
235+ Navigate,
236+ + Outlet,
237+ } from 'react-router-dom';
238+ import { useApiConfig } from '#core/api';
239+ + import { AuthContext } from '#core/auth';
240+ import { LoginScene, ListScene } from '#scenes';
241+ - import { switchRoutes } from './routes';
242+ + import { switchRoutes, linkRoutes } from './routes';
243+
244+ export const RouterComponent: React.FC = () => {
245+ return (
246+ <HashRouter>
247+ <AppRoutes />
248+ </HashRouter>
249+ );
250+ };
251+
252+ + const PrivateRoutes = () => {
253+ + const { userSession } = React.useContext(AuthContext);
254+ + return userSession?.userName ? (
255+ + <Outlet />
256+ + ) : (
257+ + <Navigate to={linkRoutes.login} />
258+ + );
259+ + };
260+
261+ const AppRoutes: React.FC = () => {
262+ useApiConfig();
263+ return (
264+ <Routes>
265+ <Route path={switchRoutes.login} element={<LoginScene />} />
266+ + <Route element={<PrivateRoutes />}>
267+ + <Route path={switchRoutes.list} element={<ListScene />} />
268+ + </Route>
269+ <Route
270+ path={switchRoutes.root}
271+ element={<Navigate to={switchRoutes.login} />}
272+ />
273+ </Routes>
274+ );
275+ };
270276
271- ...
272277```
273278
279+ > Try to navigate to /list without login.
280+
274281# Using CORS
275282
276- - Let's update example to check if it's working with cors:
283+ Let's update example to check if it's working with cors:
277284
278285``` bash
279286npm install cors --save
287+ npm install @types/cors --save-dev
280288```
281289
282- > NOTE: we can install @ types/ cors for Typescript.
290+ Configure cors:
283291
284- _ ./back/src/core/servers/express .server.ts_
292+ _ ./back/src/core/servers/rest-api .server.ts_
285293
286294``` diff
287295import express from 'express';
288296+ import cors from 'cors';
289- import cookieParser from 'cookie-parser';
290297
291- export const createApp = () => {
298+ export const createRestApiServer = () => {
292299 const app = express();
293-
294300 app.use(express.json());
295301+ app.use(
296302+ cors({
297303+ credentials: true,
298304+ origin: '*',
299305+ })
300306+ );
301- app.use(cookieParser());
302307
303308 return app;
304309};
305310
306311```
307312
308- - Update front:
313+ > In a real scenario we should set ` origin ` to the real domain, for example: ` http://my-domain.com ` .
309314
310- _ ./front/config/webapck/dev.js_
315+ Update front:
316+
317+ _ ./front/vite.config.ts_
311318
312319``` diff
313320...
314- devServer: {
315- inline: true,
316- host: 'localhost',
317- port: 8080,
318- stats: 'minimal',
319- hot: true,
320- - proxy: {
321- - '/api': 'http://localhost:8081',
322- - },
323- },
321+ plugins: [react()],
322+ - server: {
323+ - proxy: {
324+ - '/api': 'http://localhost:3000',
325+ - },
326+ - },
327+ });
328+
324329```
325330
326- - Update login request:
331+ Update login request:
327332
328333_ ./front/src/pods/login/api/login.api.ts_
329334
330335``` diff
331- import Axios from 'axios';
332- import { UserSession } from './login.api-model';
336+ ...
333337
334338- const url = '/api/security/login';
335- + const url = 'http://localhost:8081/api/security/login';
339+ + const url = 'http://localhost:3000/api/security/login';
340+
341+ ...
342+
343+ ```
344+
345+ Update logout request:
346+
347+ _ ./front/src/core/app-bar/api/app-bar.api.ts_
348+
349+ ``` diff
350+ ...
351+
352+ - const url = '/api/security/logout';
353+ + const url = 'http://localhost:3000/api/security/logout';
336354
337355...
338356
339357```
340358
341- - Update list requests:
359+ Update list requests:
342360
343361_ ./front/src/pods/list/api/list.api.ts_
344362
345363``` diff
346- import Axios from 'axios';
347- import { Item } from './list.api-model';
364+ ...
348365
349366- const clientUrl = '/api/clients';
350- + const clientUrl = 'http://localhost:8081 /api/clients';
367+ + const clientUrl = 'http://localhost:3000 /api/clients';
351368- const orderUrl = '/api/orders';
352- + const orderUrl = 'http://localhost:8081 /api/orders';
369+ + const orderUrl = 'http://localhost:3000 /api/orders';
353370
354371...
355372
0 commit comments