Skip to content

Commit 1a73e36

Browse files
rootroot
authored andcommitted
update(other): 🧩 update loading screen and logic of reProtect
update loading screen and logic of reProtect
1 parent cfdc3a2 commit 1a73e36

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1816
-966
lines changed

.husky/pre-commit

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
#!/usr/bin/env sh
22
. "$(dirname -- "$0")/_/husky.sh"
33

4-
# npm run pre-commit
4+
npm run pre-commit

.prettierignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Ignore all HTML files:
2+
*.html

.vscode/settings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,5 @@
2222
"source.formatDocument",
2323
"source.fixAll.tslint",
2424
"source.fixAll.eslint"
25-
]
25+
],
2626
}

README.md

Lines changed: 114 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -314,19 +314,124 @@ As you can see, in react you must know more than and do more than, to create hel
314314
315315
<h3 id="protect">Protect on route</h3>
316316
317-
You can protect route by using the **handle.protect method**.
318-
Imagine that you have a route only allow V.I.P user, then you need to prevent other user enter that V.I.P route. In this case you can use protect route to resolve it. See code below
317+
You can protect route by using the [meta options and use beforeEach event to execute it](https://router.vuejs.org/guide/advanced/meta.html#route-meta-fields).
318+
We will make an example in this project. The PRD for protect route's case has some short description.
319+
320+
```markdown
321+
// PRD - Comment Page
322+
323+
**Description**
324+
325+
- Comment Page is the page contains full list of comments.
326+
- The user can enter Comment Page with two ways:
327+
328+
1. Click "See more" from comment section in Content Page.
329+
2. copy and paste the url of Comment Page in browser's url bar.
330+
331+
**Accessible rules**
332+
To access Comment Page user must:
333+
334+
- Already logged
335+
336+
If user haven't logged before, the system will auto redirect user to Login Page.
337+
338+
If user have an account before, user will logged with that account, and after login success, the system will redirect user back to Comment Page.
339+
340+
If user does not have an account before, user can go to Register Page and regist an account. After regist success, the system will auto login and redirect user go to Comment Page.
341+
```
342+
343+
You will have many choice to resolve for above PRD
344+
345+
1. Use React Hook and Store (easy way to handle but never easy way to manage)
346+
347+
- Router load Comment Page finish
348+
- Comment Page's hook actived
349+
- Check access rule. If invalid then store current path and redirect to Login Page
350+
- Login success redirect back to Comment Page path stored and remember clear that store's path variable.
351+
352+
2. Use only react-router (harder to implement but easy to use and manage)
353+
354+
- Setup **handle { protect() {... return boolean | string} }** and execute it in **RouterProtection** render-less.
355+
- If **protect()** return invalid, then the system will auto check if Comment Page need to back after success verify, then save the path of Comment Page, and redirect user to Login Page.
356+
- Login success redirect back to Comment Page.
357+
358+
In this project, I will show you the second solution. Cause we just focus only react-router in this project, and cause redirect is a part of router's cases, so doesn't need use store and hook to resolve it.
359+
360+
I handled for you executing **protect()** in this project, so you just only focus how to use it easy way. See code below
319361
320362
```javascript
363+
// router/index
364+
365+
// Init RouterProtection with WAITING_VERIFY_ROUTER_ID_LIST
321366
{
322-
path: import.meta.env.ROUTER_CONTENT_PATH,
323-
element: withLazy(() => import('pages/ContentPage')),
367+
path: import.meta.env.ROUTER_BASE_PATH,
368+
element: (
369+
<RouterInit>
370+
...
371+
<RouterProtection
372+
WatingVerifyRouterIDList={WAITING_VERIFY_ROUTER_ID_LIST}
373+
>
374+
<Layout />
375+
</RouterProtection>
376+
...
377+
</RouterInit>
378+
),
379+
}
380+
381+
// Config Protect method
382+
{
383+
id: import.meta.env.ROUTER_COMMENT_ID,
384+
path: import.meta.env.ROUTER_COMMENT_PATH,
385+
element: withLazy(() => import('pages/CommentPage')),
386+
324387
handle: {
325-
protect() {
326-
const userInfo = useUserInfo()
327-
return userInfo.isVip
328-
}
388+
protect(certInfo) {
389+
/**
390+
* certInfo param contains
391+
* {
392+
* user: {email?: string}
393+
* navigateInfo: {to: RouteLocationNormalized, from: RouteLocationNormalized}
394+
* successPath: string
395+
* }
396+
*/
397+
const userInfo = certInfo?.user
398+
399+
if (!userInfo || !userInfo.email)
400+
return import.meta.env.ROUTER_LOGIN_PATH
401+
402+
return true
403+
},
329404
},
405+
},
406+
{
407+
id: import.meta.env.ROUTER_LOGIN_ID,
408+
path: import.meta.env.ROUTER_LOGIN_PATH,
409+
element: withLazy(() => import('pages/LoginPage')),
410+
handle: {
411+
protect(certInfo) {
412+
const userInfo = certInfo?.user
413+
414+
if (userInfo && userInfo.email) {
415+
// NOTE - If logged > redirect to successPath OR previous path OR Home Page path
416+
417+
return certInfo.successPath
418+
? certInfo.successPath
419+
: certInfo.navigateInfo?.from
420+
? certInfo.navigateInfo.from.fullPath
421+
: import.meta.env.ROUTER_HOME_PATH
422+
}
423+
424+
return true
425+
},
426+
},
427+
}, // Login Page
330428
```
331429
332-
Makesure your protect function is a **Pure Function**, it make your result will always right.
430+
**NOTE**
431+
432+
- Makesure your protect function is a **Pure Function**, it make your result will always right.
433+
- You can customize or implement your logic to handle protect case by using
434+
435+
1. **shim-vue.d.ts** to declare type for **meta field**
436+
2. **config/router/utils/BeforeEachHandler.ts** to customize or implement logic.
437+
3. **config/router/index.ts** to init your handler.

config/.eslintrc-auto-import.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"createRef": true,
1919
"createRoot": true,
2020
"forwardRef": true,
21+
"generatePath": true,
2122
"keyframes": true,
2223
"lazy": true,
2324
"memo": true,
@@ -37,6 +38,7 @@
3738
"useLayoutEffect": true,
3839
"useLinkClickHandler": true,
3940
"useLocation": true,
41+
"useMatches": true,
4042
"useMemo": true,
4143
"useNavigate": true,
4244
"useNavigationType": true,

config/auto-imports.d.ts

Lines changed: 53 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,57 @@
11
// Generated by 'unplugin-auto-import'
22
export {}
33
declare global {
4-
const BrowserRouter: typeof import('react-router-dom')['BrowserRouter']
5-
const Link: typeof import('react-router-dom')['Link']
6-
const NavLink: typeof import('react-router-dom')['NavLink']
7-
const Navigate: typeof import('react-router-dom')['Navigate']
8-
const Outlet: typeof import('react-router-dom')['Outlet']
9-
const React: typeof import('react')
10-
const Route: typeof import('react-router-dom')['Route']
11-
const RouterProvider: typeof import('react-router-dom')['RouterProvider']
12-
const Routes: typeof import('react-router-dom')['Routes']
13-
const StrictMode: typeof import('react')['StrictMode']
14-
const Suspense: typeof import('react')['Suspense']
15-
const componentDidCatch: typeof import('react')['componentDidCatch']
16-
const createBrowserRouter: typeof import('react-router-dom')['createBrowserRouter']
17-
const createContext: typeof import('react')['createContext']
18-
const createGlobalStyle: typeof import('styled-components')['createGlobalStyle']
19-
const createRef: typeof import('react')['createRef']
20-
const createRoot: typeof import('react-dom/client')['createRoot']
21-
const forwardRef: typeof import('react')['forwardRef']
22-
const keyframes: typeof import('styled-components')['keyframes']
23-
const lazy: typeof import('react')['lazy']
24-
const memo: typeof import('react')['memo']
25-
const rgba: typeof import('polished')['rgba']
26-
const startTransition: typeof import('react')['startTransition']
27-
const styled: typeof import('styled-components')['default']
28-
const useCallback: typeof import('react')['useCallback']
29-
const useContext: typeof import('react')['useContext']
30-
const useDebugValue: typeof import('react')['useDebugValue']
31-
const useDeferredValue: typeof import('react')['useDeferredValue']
32-
const useEffect: typeof import('react')['useEffect']
33-
const useHref: typeof import('react-router-dom')['useHref']
34-
const useId: typeof import('react')['useId']
35-
const useImperativeHandle: typeof import('react')['useImperativeHandle']
36-
const useInRouterContext: typeof import('react-router-dom')['useInRouterContext']
37-
const useInsertionEffect: typeof import('react')['useInsertionEffect']
38-
const useLayoutEffect: typeof import('react')['useLayoutEffect']
39-
const useLinkClickHandler: typeof import('react-router-dom')['useLinkClickHandler']
40-
const useLocation: typeof import('react-router-dom')['useLocation']
41-
const useMemo: typeof import('react')['useMemo']
42-
const useNavigate: typeof import('react-router-dom')['useNavigate']
43-
const useNavigationType: typeof import('react-router-dom')['useNavigationType']
44-
const useOutlet: typeof import('react-router-dom')['useOutlet']
45-
const useOutletContext: typeof import('react-router-dom')['useOutletContext']
46-
const useParams: typeof import('react-router-dom')['useParams']
47-
const useReducer: typeof import('react')['useReducer']
48-
const useRef: typeof import('react')['useRef']
49-
const useResolvedPath: typeof import('react-router-dom')['useResolvedPath']
50-
const useRoutes: typeof import('react-router-dom')['useRoutes']
51-
const useSearchParams: typeof import('react-router-dom')['useSearchParams']
52-
const useState: typeof import('react')['useState']
53-
const useSyncExternalStore: typeof import('react')['useSyncExternalStore']
54-
const useTransition: typeof import('react')['useTransition']
4+
const BrowserRouter: typeof import('react-router-dom')['BrowserRouter']
5+
const Link: typeof import('react-router-dom')['Link']
6+
const NavLink: typeof import('react-router-dom')['NavLink']
7+
const Navigate: typeof import('react-router-dom')['Navigate']
8+
const Outlet: typeof import('react-router-dom')['Outlet']
9+
const React: typeof import('react')
10+
const Route: typeof import('react-router-dom')['Route']
11+
const RouterProvider: typeof import('react-router-dom')['RouterProvider']
12+
const Routes: typeof import('react-router-dom')['Routes']
13+
const StrictMode: typeof import('react')['StrictMode']
14+
const Suspense: typeof import('react')['Suspense']
15+
const componentDidCatch: typeof import('react')['componentDidCatch']
16+
const createBrowserRouter: typeof import('react-router-dom')['createBrowserRouter']
17+
const createContext: typeof import('react')['createContext']
18+
const createGlobalStyle: typeof import('styled-components')['createGlobalStyle']
19+
const createRef: typeof import('react')['createRef']
20+
const createRoot: typeof import('react-dom/client')['createRoot']
21+
const forwardRef: typeof import('react')['forwardRef']
22+
const generatePath: typeof import('react-router-dom')['generatePath']
23+
const keyframes: typeof import('styled-components')['keyframes']
24+
const lazy: typeof import('react')['lazy']
25+
const memo: typeof import('react')['memo']
26+
const rgba: typeof import('polished')['rgba']
27+
const startTransition: typeof import('react')['startTransition']
28+
const styled: typeof import('styled-components')['default']
29+
const useCallback: typeof import('react')['useCallback']
30+
const useContext: typeof import('react')['useContext']
31+
const useDebugValue: typeof import('react')['useDebugValue']
32+
const useDeferredValue: typeof import('react')['useDeferredValue']
33+
const useEffect: typeof import('react')['useEffect']
34+
const useHref: typeof import('react-router-dom')['useHref']
35+
const useId: typeof import('react')['useId']
36+
const useImperativeHandle: typeof import('react')['useImperativeHandle']
37+
const useInRouterContext: typeof import('react-router-dom')['useInRouterContext']
38+
const useInsertionEffect: typeof import('react')['useInsertionEffect']
39+
const useLayoutEffect: typeof import('react')['useLayoutEffect']
40+
const useLinkClickHandler: typeof import('react-router-dom')['useLinkClickHandler']
41+
const useLocation: typeof import('react-router-dom')['useLocation']
42+
const useMatches: typeof import('react-router-dom')['useMatches']
43+
const useMemo: typeof import('react')['useMemo']
44+
const useNavigate: typeof import('react-router-dom')['useNavigate']
45+
const useNavigationType: typeof import('react-router-dom')['useNavigationType']
46+
const useOutlet: typeof import('react-router-dom')['useOutlet']
47+
const useOutletContext: typeof import('react-router-dom')['useOutletContext']
48+
const useParams: typeof import('react-router-dom')['useParams']
49+
const useReducer: typeof import('react')['useReducer']
50+
const useRef: typeof import('react')['useRef']
51+
const useResolvedPath: typeof import('react-router-dom')['useResolvedPath']
52+
const useRoutes: typeof import('react-router-dom')['useRoutes']
53+
const useSearchParams: typeof import('react-router-dom')['useSearchParams']
54+
const useState: typeof import('react')['useState']
55+
const useSyncExternalStore: typeof import('react')['useSyncExternalStore']
56+
const useTransition: typeof import('react')['useTransition']
5557
}

config/eslint.config.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ module.exports = {
1515
'plugin:import/warnings',
1616
'prettier',
1717
],
18-
plugins: ['react', '@typescript-eslint'],
18+
plugins: ['react', '@typescript-eslint/eslint-plugin'],
1919
env: {
2020
browser: true,
2121
es6: true,
@@ -29,6 +29,11 @@ module.exports = {
2929
},
3030
parser: '@typescript-eslint/parser',
3131
parserOptions: {
32+
parser: {
33+
js: 'espree',
34+
jsx: 'espree',
35+
'<template>': 'espree',
36+
},
3237
ecmaFeatures: {
3338
jsx: true,
3439
tsx: true,
@@ -49,8 +54,6 @@ module.exports = {
4954
'no-unused-vars': 'warn',
5055
'react-hooks/rules-of-hooks': 'warn',
5156
'react-hooks/exhaustive-deps': 'warn',
52-
// NOTE - This options settup for stop linting alias
53-
// "import/no-unresolved": [0, { }]
5457
},
5558
settings: {
5659
'import/resolver': {

0 commit comments

Comments
 (0)