Browse Source

some thunk experiments + flush cache

asmer 1 month ago
parent
commit
952a27a733
4 changed files with 136 additions and 15 deletions
  1. 114 9
      src/App.tsx
  2. 13 1
      src/lib/pub/query/index.ts
  3. 4 2
      src/lib/queryRoute/index.tsx
  4. 5 3
      src/lib/router/index.tsx

+ 114 - 9
src/App.tsx

@@ -5,7 +5,7 @@ import {Router, Link} from 'react-router-dom'
 import {createQueryPub, NamedRoute, NamedLink, usePub} from './lib';
 import {MetaPlate} from './lib';
 
-import {createQueryRoutes} from './lib';
+import {createQueryRoutes, createPub} from './lib';
 
 /*
   CREATE QUERY ROUTE HUGE CONFIGURATION SAMPLE/TEST
@@ -13,10 +13,6 @@ import {createQueryRoutes} from './lib';
 
 const history = createBrowserHistory()
 
-const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOnsiaWQiOiI2NjdmZjBkYTIyMzIxMjBjN2M4NzFmN2MiLCJsb2dpbiI6InRzdDE5IiwiYWNsIjpbIjY2N2ZmMGRhMjIzMjEyMGM3Yzg3MWY3YyIsInVzZXIiXX0sImlhdCI6MTcyMDI1OTEwN30.eDcInxQlskt32LjaCe5sdCcJ3B97BKYZtgUARxThYQM'
-
-//console.log(JSON.parse(atob(token.split('.')[1])).sub.id)
-
 const shopUrl = 'http://shop-roles.node.ed.asmer.org.ua/'
 
 const gql = (query, variables={}) => 
@@ -25,7 +21,8 @@ const gql = (query, variables={}) =>
         headers: {
             'Content-Type': 'application/json',
             Accept: 'application/json',
-            Authorization: 'Bearer ' + token
+            ...(authPub.token ? 
+             { Authorization: 'Bearer ' + authPub.token } : {})
         },
         body: JSON.stringify({query, variables})
     })
@@ -245,13 +242,120 @@ const queryRouteResult = createQueryRoutes({
                 }
             `, {query: JSON.stringify([{_id}])}],
             component: PageCategory
+        },
+        login: {
+            isMutation: true,
+            args: ({login, password}) => [`query login ($login:String, $password: String){
+                login(login:$login, password: $password)
+            }`, {login, password}]
+        },
+        user: {
+            args: ({_id}) => [`query userById($query:String){
+                      UserFindOne(query: $query){
+                        _id login nick
+                        avatar { url }
+                    }
+                }
+            `, {query: JSON.stringify([{_id}])}],
         }
     }
 })
 
-const { AllRoutes, queryRoutes: {category: {CategoryLink}}, queryPub } = queryRouteResult
+const { AllRoutes, 
+        queryRoutes: 
+            {
+                category: {CategoryLink}, 
+                login: {useLoginMutation, query: loginQuery},
+                user: {query: userQuery}
+            }, 
+       queryPub, withQueryFunc, flushCache } = queryRouteResult
+
 
-//queryPub.subscribe(() => console.log(JSON.stringify(queryPub, null, 4)))
+const authPub = createPub()
+const jwtDecode = token => {
+    try {
+        return JSON.parse(atob(token.split('.')[1]))
+    }
+    catch{ }
+}
+
+const actionLogout = () => {
+    authPub.login = null
+    authPub.token = null;
+    authPub.user = null;
+    authPub.decoded = null
+
+
+    flushCache()
+}
+
+const thunkLogin = async ({login, password}) => {
+    const loginResult = await loginQuery({login, password})
+    if (!loginResult || !loginResult?.payload){
+        actionLogout()
+        return;
+    }
+    const token = loginResult.payload
+    const decoded = jwtDecode(token)
+    if (!decoded){
+        actionLogout()
+        return;
+    }
+
+    authPub.login = decoded.sub.login
+    authPub.token = token
+    authPub.decoded = decoded
+
+    const myUser = await userQuery({_id: decoded.sub.id})
+    if (!myUser.payload){
+        actionLogout()
+        return;
+    }
+    authPub.user = myUser.payload
+}
+
+//authPub.subscribe(() => console.log(JSON.stringify(authPub, null, 4)))
+
+
+const LoginForm = () => {
+    const [login, setLogin] = useState('')
+    const [password, setPassword] = useState('')
+
+    return (
+        <div>
+            <input value={login} onChange={e => setLogin(e.target.value)} />
+            <input value={password} onChange={e => setPassword(e.target.value)} />
+            <button onClick={() => thunkLogin({login, password})}>Login...</button>
+        </div>
+    )
+}
+
+const LogoutButton = () => {
+    usePub(authPub)
+    if (!authPub.login) return null;
+    return (
+        <button onClick={actionLogout}>{authPub.user?.nick || authPub.login} (logout)</button>
+    )
+}
+
+
+//works okay
+//const LoginForm = () => {
+    //const [login, setLogin] = useState('')
+    //const [password, setPassword] = useState('')
+
+    //const [loginQuery, data] = useLoginMutation()
+    //console.log(loginQuery, data);
+    //return (
+        //<div>
+            //<input value={login} onChange={e => setLogin(e.target.value)} />
+            //<input value={password} onChange={e => setPassword(e.target.value)} />
+            //<button onClick={() => loginQuery({login, password})}>Login...</button>
+        //</div>
+    //)
+//}
+
+//queryPub.subscribe(() => console.log(queryPub, JSON.stringify(queryPub, null, 4)))
 
 function App() {
     //const {payload} = useCategoriesQuery()
@@ -259,7 +363,8 @@ function App() {
     //useEffect(() => console.log('effect',performance.now()), [payload])
     return (
         <Router history={history}>
-
+            <LogoutButton/>
+            <LoginForm />
             <AllRoutes />
 
 

+ 13 - 1
src/lib/pub/query/index.ts

@@ -96,6 +96,7 @@ export default (options:CreateQueryPubOptions) => {
                 }
             }
 
+
             /*
              * Performs query, if needed, using makeQuery or forceQuery
              * Checks is query mutation or pure query, and options like avoidRepeatInProgress or 
@@ -225,5 +226,16 @@ export default (options:CreateQueryPubOptions) => {
         }
     }
 
-    return {queryPub, withQueryFunc, ...(options.queryFunc ? {createQuery: withQueryFunc(options.queryFunc)}: {})}
+
+    const flushCache = () => {
+        for (const promiseName of Object.keys(queryPub.queries)){
+            delete queryPub.queries[promiseName]
+        }
+
+        for (const promiseName of Object.keys(queryPub.mutations)){
+            delete queryPub.mutations[promiseName]
+        }
+    }
+
+    return {queryPub, withQueryFunc, ...(options.queryFunc ? {createQuery: withQueryFunc(options.queryFunc)}: {}), flushCache}
 }

+ 4 - 2
src/lib/queryRoute/index.tsx

@@ -81,6 +81,7 @@ export type QueryRouteResult = {
     makeQuery: Function,
     query: Function,
     forceQuery: Function,
+    flushCache: Function,
     hook: Function,
 
     //named hook useNameQuery
@@ -211,11 +212,11 @@ export const createQueryRoutes = (options:CreateQueryRoutesOptions):CreateQueryR
     const AllRoutes = () => 
         (
             <>
-                {Object.entries(queryRoutesResults).map(([key,{Route}]) => <Route key={key}/>)}
+                {Object.entries(queryRoutesResults).map(([key,{Route}]) => Route ? <Route key={key}/> : null)}
             </>
         )
 
-    const {queryPub, withQueryFunc, createQuery} = queryPubResult
+    const {queryPub, withQueryFunc, createQuery, flushCache} = queryPubResult
 
     return {
         NamedRoute: Route,
@@ -226,6 +227,7 @@ export const createQueryRoutes = (options:CreateQueryRoutesOptions):CreateQueryR
         queryPub,
         withQueryFunc,
         createQuery,
+        flushCache,
 
 
         queryRoutes: queryRoutesResults,

+ 5 - 3
src/lib/router/index.tsx

@@ -23,8 +23,10 @@ export const NamedRoute = ({name, routeName, query, pendingQueryComponent:P, err
                     const [queryPub, key] = query.getQueryPubBranch(props.match.params)
                     const pubToState = () => {
                         if (!queryPub[key]){ 
-                            setQueryError()
-                            setQueryResult()
+                            if (queryError || queryResult){
+                                setQueryError()
+                                setQueryResult()
+                            }
                             return
                         }
                         const {status, payload, error} = queryPub[key];
@@ -55,7 +57,7 @@ export const NamedRoute = ({name, routeName, query, pendingQueryComponent:P, err
                 }
             }
             return () => {
-                console.log('UNMOUNT', props.match.params)
+                //console.log('UNMOUNT', props.match.params)
                 setQueryError()
                 setQueryResult()
                 if (queryPubUnsubscribeRef.current)