Dwayne Harris 5 years ago
parent
commit
f61e1e1271
  1. 241
      package-lock.json
  2. 20
      package.json
  3. 11
      src/actions/authentication.ts
  4. 12
      src/components/app/app.scss
  5. 5
      src/components/app/app.tsx
  6. 7
      src/components/app/index.ts
  7. 44
      src/components/create-group-step/create-group-step.tsx
  8. 13
      src/components/create-group-step/index.ts
  9. 27
      src/components/create-user-step/create-user-step.tsx
  10. 5
      src/components/create-user-step/index.ts
  11. 49
      src/components/group-list/group-list-item/index.tsx
  12. 17
      src/components/group-list/index.tsx
  13. 8
      src/components/pages/directory/directory.tsx
  14. 2
      src/components/pages/register-group/index.ts
  15. 11
      src/components/pages/register/index.ts
  16. 8
      src/components/pages/register/register.tsx
  17. 5
      src/components/pages/self/index.ts
  18. 11
      src/components/pages/self/self.tsx
  19. 17
      src/components/user-info/index.ts
  20. 56
      src/components/user-info/user-info.tsx
  21. 7
      src/reducers/authentication.ts
  22. 1
      src/selectors/authentication.ts
  23. 4
      src/selectors/directory.ts
  24. 6
      src/selectors/entities.ts
  25. 2
      src/types/entities.ts
  26. 29
      src/types/index.ts
  27. 1
      src/types/store.ts

241
package-lock.json

@ -13,24 +13,24 @@
}
},
"@fortawesome/fontawesome-common-types": {
"version": "0.2.22",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.22.tgz",
"integrity": "sha512-QmEuZsipX5/cR9JOg0fsTN4Yr/9lieYWM8AQpmRa0eIfeOcl/HLYoEa366BCGRSrgNJEexuvOgbq9jnJ22IY5g=="
"version": "0.2.24",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.24.tgz",
"integrity": "sha512-IPBT/1LdUVQpHcqdrh8uI2/86Fbu7933hkA/HweiCmP5QgF/8PecFM00gYvykxf0RZud8bg8zu+YfggDFUc1Kw=="
},
"@fortawesome/fontawesome-svg-core": {
"version": "1.2.22",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.22.tgz",
"integrity": "sha512-Q941E4x8UfnMH3308n0qrgoja+GoqyiV846JTLoCcCWAKokLKrixCkq6RDBs8r+TtAWaLUrBpI+JFxQNX/WNPQ==",
"version": "1.2.24",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.24.tgz",
"integrity": "sha512-9uVGOEZwviZKbkOVX8nn8cErVqOHBAd1Fqd2OH7Iwu0vxGWdb3fFOMhaAyMXUHZpq1u5C9/HClCV49ci4WmJAg==",
"requires": {
"@fortawesome/fontawesome-common-types": "^0.2.22"
"@fortawesome/fontawesome-common-types": "^0.2.24"
}
},
"@fortawesome/free-solid-svg-icons": {
"version": "5.10.2",
"resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.10.2.tgz",
"integrity": "sha512-9Os/GRUcy+iVaznlg8GKcPSQFpIQpAg14jF0DWsMdnpJfIftlvfaQCWniR/ex9FoOpSEOrlXqmUCFL+JGeciuA==",
"version": "5.11.1",
"resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.11.1.tgz",
"integrity": "sha512-bB3hXON1K6mVOetTTg5VXZ4CAHg866p7MqenDkJ/eVcbWbGQRE45ojHEwkf37tWx3E8z6lcEameRwU9r5tGwjg==",
"requires": {
"@fortawesome/fontawesome-common-types": "^0.2.22"
"@fortawesome/fontawesome-common-types": "^0.2.24"
}
},
"@fortawesome/react-fontawesome": {
@ -1907,9 +1907,9 @@
}
},
"cyclist": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz",
"integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=",
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz",
"integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=",
"dev": true
},
"dashdash": {
@ -2217,9 +2217,9 @@
"dev": true
},
"elliptic": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.0.tgz",
"integrity": "sha512-eFOJTMyCYb7xtE/caJ6JJu+bhi67WCYNbkGSknu20pmM8Ke/bqOfdnZWxyoGN26JgfxTbXrsCkEw4KheCT/KGg==",
"version": "6.5.1",
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.1.tgz",
"integrity": "sha512-xvJINNLbTeWQjrl6X+7eQCrIy/YPv5XCpKW6kB5mKvtnGILoLDcySuwomfdzt0BMdLNVnuRNTuzKNHj0bva1Cg==",
"dev": true,
"requires": {
"bn.js": "^4.4.0",
@ -2362,9 +2362,9 @@
"dev": true
},
"eventemitter3": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz",
"integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==",
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.0.tgz",
"integrity": "sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==",
"dev": true
},
"events": {
@ -2794,9 +2794,9 @@
}
},
"follow-redirects": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.8.1.tgz",
"integrity": "sha512-micCIbldHioIegeKs41DoH0KS3AXfFzgS30qVkM6z/XOE/GJgvmsoc839NUqa1B9udYe9dQxgv7KFwng6+p/dw==",
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.9.0.tgz",
"integrity": "sha512-CRcPzsSIbXyVDl0QI01muNDu69S8trU4jArW9LpOt2WtC6LyUJetcIrmfHsRBx7/Jb6GHJUiuqyYxPooFfNt6A==",
"dev": true,
"requires": {
"debug": "^3.0.0"
@ -3813,16 +3813,16 @@
"dev": true
},
"history": {
"version": "4.9.0",
"resolved": "https://registry.npmjs.org/history/-/history-4.9.0.tgz",
"integrity": "sha512-H2DkjCjXf0Op9OAr6nJ56fcRkTSNrUiv41vNJ6IswJjif6wlpZK0BTfFbi7qK9dXLSYZxkq5lBsj3vUjlYBYZA==",
"version": "4.10.1",
"resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz",
"integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==",
"requires": {
"@babel/runtime": "^7.1.2",
"loose-envify": "^1.2.0",
"resolve-pathname": "^2.2.0",
"resolve-pathname": "^3.0.0",
"tiny-invariant": "^1.0.2",
"tiny-warning": "^1.0.0",
"value-equal": "^0.4.0"
"value-equal": "^1.0.1"
}
},
"hmac-drbg": {
@ -4008,12 +4008,12 @@
"dev": true
},
"http-proxy": {
"version": "1.17.0",
"resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz",
"integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==",
"version": "1.18.0",
"resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.0.tgz",
"integrity": "sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ==",
"dev": true,
"requires": {
"eventemitter3": "^3.0.0",
"eventemitter3": "^4.0.0",
"follow-redirects": "^1.0.0",
"requires-port": "^1.0.0"
}
@ -4301,9 +4301,9 @@
"dev": true
},
"is-absolute-url": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.1.tgz",
"integrity": "sha512-c2QjUwuMxLsld90sj3xYzpFYWJtuxkIn1f5ua9RTEYJt/vV2IsM+Py00/6qjV7qExgifUvt7qfyBGBBKm+2iBg==",
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.2.tgz",
"integrity": "sha512-+5g/wLlcm1AcxSP7014m6GvbPHswDx980vD/3bZaap8aGV9Yfs7Q6y6tfaupgZ5O74Byzc8dGrSCJ+bFXx0KdA==",
"dev": true
},
"is-accessor-descriptor": {
@ -4705,9 +4705,9 @@
"dev": true
},
"loglevel": {
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.3.tgz",
"integrity": "sha512-LoEDv5pgpvWgPF4kNYuIp0qqSJVWak/dML0RY74xlzMZiT9w77teNAwKYKWBTYjlokMirg+o3jBwp+vlLrcfAA==",
"version": "1.6.4",
"resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.4.tgz",
"integrity": "sha512-p0b6mOGKcGa+7nnmKbpzR6qloPbrgLcnio++E+14Vo/XffOGwZtRpUhr8dTH/x2oCMmEoIU0Zwm3ZauhvYD17g==",
"dev": true
},
"loose-envify": {
@ -5118,9 +5118,9 @@
}
},
"node-forge": {
"version": "0.7.5",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.5.tgz",
"integrity": "sha512-MmbQJ2MTESTjt3Gi/3yG1wGpIMhUfcIypUCGtTizFR9IiccFwxSpfp0vtIZlkFclEqERemxfnSdZEMR9VqqEFQ==",
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.8.2.tgz",
"integrity": "sha512-mXQ9GBq1N3uDCyV1pdSzgIguwgtVpM7f5/5J4ipz12PKWElmPpVWLDuWl8iXmhysr21+WmX/OJ5UKx82wjomgg==",
"dev": true
},
"node-gyp": {
@ -5621,12 +5621,12 @@
"dev": true
},
"parallel-transform": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.1.0.tgz",
"integrity": "sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=",
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz",
"integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==",
"dev": true,
"requires": {
"cyclist": "~0.2.2",
"cyclist": "^1.0.1",
"inherits": "^2.0.3",
"readable-stream": "^2.1.5"
}
@ -5641,9 +5641,9 @@
}
},
"parse-asn1": {
"version": "5.1.4",
"resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.4.tgz",
"integrity": "sha512-Qs5duJcuvNExRfFZ99HDD3z4mAi3r9Wl/FOjEOijlxwCZs7E7mW2vjTpgQ4J8LpTF8x5v+1Vn5UQFejmWT11aw==",
"version": "5.1.5",
"resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz",
"integrity": "sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==",
"dev": true,
"requires": {
"asn1.js": "^4.0.0",
@ -5809,9 +5809,9 @@
}
},
"portfinder": {
"version": "1.0.23",
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.23.tgz",
"integrity": "sha512-B729mL/uLklxtxuiJKfQ84WPxNw5a7Yhx3geQZdcA4GjNjZSTSSMMWyoennMVnTWSmAR0lMdzWYN0JLnHrg1KQ==",
"version": "1.0.24",
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.24.tgz",
"integrity": "sha512-ekRl7zD2qxYndYflwiryJwMioBI7LI7rVXg3EnLK3sjkouT5eOuhS3gS255XxBksa30VG8UPZYZCdgfGOfkSUg==",
"dev": true,
"requires": {
"async": "^1.5.2",
@ -6666,9 +6666,9 @@
"dev": true
},
"resolve-pathname": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-2.2.0.tgz",
"integrity": "sha512-bAFz9ld18RzJfddgrO2e/0S2O81710++chRMUxHjXOYKF6jTAMrUNZrEZ1PvV0zlhfjidm08iRPdTLPno1FuRg=="
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz",
"integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng=="
},
"resolve-url": {
"version": "0.2.1",
@ -6964,12 +6964,12 @@
"dev": true
},
"selfsigned": {
"version": "1.10.4",
"resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.4.tgz",
"integrity": "sha512-9AukTiDmHXGXWtWjembZ5NDmVvP2695EtpgbCsxCa68w3c88B+alqbmZ4O3hZ4VWGXeGWzEVdvqgAJD8DQPCDw==",
"version": "1.10.6",
"resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.6.tgz",
"integrity": "sha512-i3+CeqxL7DpAazgVpAGdKMwHuL63B5nhJMh9NQ7xmChGkA3jNFflq6Jyo1LLJYcr3idWiNOPWHCrm4zMayLG4w==",
"dev": true,
"requires": {
"node-forge": "0.7.5"
"node-forge": "0.8.2"
}
},
"semver": {
@ -7008,9 +7008,9 @@
}
},
"serialize-javascript": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.8.0.tgz",
"integrity": "sha512-3tHgtF4OzDmeKYj6V9nSyceRS0UJ3C7VqyD2Yj28vC/z2j6jG5FmFGahOKMD9CrglxTm3tETr87jEypaYV8DUg==",
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.9.1.tgz",
"integrity": "sha512-0Vb/54WJ6k5v8sSWN09S0ora+Hnr+cX40r9F170nT+mSkaxltoE/7R3OrIdBSUv1OoiobH1QoWQbCnAO+e8J1A==",
"dev": true
},
"serve-index": {
@ -7186,6 +7186,12 @@
"requires": {
"is-extendable": "^0.1.0"
}
},
"source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
"dev": true
}
}
},
@ -7271,9 +7277,9 @@
}
},
"sockjs-client": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.3.0.tgz",
"integrity": "sha512-R9jxEzhnnrdxLCNln0xg5uGHqMnkhPSTzUZH2eXcR03S/On9Yvoq2wyUZILRUhZCNVu2PmwWVoyuiPz8th8zbg==",
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.4.0.tgz",
"integrity": "sha512-5zaLyO8/nri5cua0VtOrFXBPK1jbL4+1cebT/mmKA1E1ZXOvJrII75bPu0l0k843G/+iAbhEqzyKr0w/eCCj7g==",
"dev": true,
"requires": {
"debug": "^3.2.5",
@ -7326,9 +7332,9 @@
"dev": true
},
"source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
},
"source-map-resolve": {
@ -7352,14 +7358,6 @@
"requires": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
},
"dependencies": {
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
}
}
},
"source-map-url": {
@ -7703,22 +7701,14 @@
}
},
"terser": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/terser/-/terser-4.2.1.tgz",
"integrity": "sha512-cGbc5utAcX4a9+2GGVX4DsenG6v0x3glnDi5hx8816X1McEAwPlPgRtXPJzSBsbpILxZ8MQMT0KvArLuE0HP5A==",
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/terser/-/terser-4.3.1.tgz",
"integrity": "sha512-pnzH6dnFEsR2aa2SJaKb1uSCl3QmIsJ8dEkj0Fky+2AwMMcC9doMqLOQIH6wVTEKaVfKVvLSk5qxPBEZT9mywg==",
"dev": true,
"requires": {
"commander": "^2.20.0",
"source-map": "~0.6.1",
"source-map-support": "~0.5.12"
},
"dependencies": {
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
}
}
},
"terser-webpack-plugin": {
@ -7736,14 +7726,6 @@
"terser": "^4.1.2",
"webpack-sources": "^1.4.0",
"worker-farm": "^1.7.0"
},
"dependencies": {
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
}
}
},
"through2": {
@ -7874,9 +7856,9 @@
}
},
"ts-loader": {
"version": "6.0.4",
"resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-6.0.4.tgz",
"integrity": "sha512-p2zJYe7OtwR+49kv4gs7v4dMrfYD1IPpOtqiSPCbe8oR+4zEBtdHwzM7A7M91F+suReqgzZrlClk4LRSSp882g==",
"version": "6.1.2",
"resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-6.1.2.tgz",
"integrity": "sha512-dudxFKm0Ellrg/gLNlu+97/UgwvoMK0SdUVImPUSzq3IcRUVtShylZvcMX+CgvCQL1BEKb913NL0gAP1GA/OFw==",
"dev": true,
"requires": {
"chalk": "^2.3.0",
@ -7887,9 +7869,9 @@
}
},
"ts-node": {
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.3.0.tgz",
"integrity": "sha512-dyNS/RqyVTDcmNM4NIBAeDMpsAdaQ+ojdf0GOLqE6nwJOgzEkdRNzJywhDfwnuvB10oa6NLVG1rUJQCpRN7qoQ==",
"version": "8.4.1",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.4.1.tgz",
"integrity": "sha512-5LpRN+mTiCs7lI5EtbXmF/HfMeCjzt7DH9CZwtkr6SywStrNQC723wG+aOWFiLNn7zT3kD/RnFqi3ZUfr4l5Qw==",
"dev": true,
"requires": {
"arg": "^4.1.0",
@ -7943,9 +7925,9 @@
"dev": true
},
"typescript": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.2.tgz",
"integrity": "sha512-lmQ4L+J6mnu3xweP8+rOrUwzmN+MRAj7TgtJtDaXE5PMyX2kCrklhg3rvOsOIfNeAWMQWO2F1GPc1kMD2vLAfw==",
"version": "3.6.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.3.tgz",
"integrity": "sha512-N7bceJL1CtRQ2RiG0AQME13ksR7DiuQh/QehubYcghzv20tnh+MQnQIuJddTmsbqYj+dztchykemz0zFzlvdQw==",
"dev": true
},
"uglify-js": {
@ -8055,9 +8037,9 @@
}
},
"upath": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/upath/-/upath-1.1.2.tgz",
"integrity": "sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==",
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz",
"integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==",
"dev": true
},
"upper-case": {
@ -8182,9 +8164,9 @@
}
},
"value-equal": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/value-equal/-/value-equal-0.4.0.tgz",
"integrity": "sha512-x+cYdNnaA3CxvMaTX0INdTCN8m8aF2uY9BvEqmxuYp8bL09cs/kWVQPVGcA35fMktdOsP69IgU7wFj/61dJHEw=="
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz",
"integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw=="
},
"vary": {
"version": "1.1.2",
@ -8230,9 +8212,9 @@
}
},
"webpack": {
"version": "4.39.3",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-4.39.3.tgz",
"integrity": "sha512-BXSI9M211JyCVc3JxHWDpze85CvjC842EvpRsVTc/d15YJGlox7GIDd38kJgWrb3ZluyvIjgenbLDMBQPDcxYQ==",
"version": "4.40.2",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-4.40.2.tgz",
"integrity": "sha512-5nIvteTDCUws2DVvP9Qe+JPla7kWPPIDFZv55To7IycHWZ+Z5qBdaBYPyuXWdhggTufZkQwfIK+5rKQTVovm2A==",
"dev": true,
"requires": {
"@webassemblyjs/ast": "1.8.5",
@ -8366,9 +8348,9 @@
}
},
"webpack-cli": {
"version": "3.3.7",
"resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.7.tgz",
"integrity": "sha512-OhTUCttAsr+IZSMVwGROGRHvT+QAs8H6/mHIl4SvhAwYywjiylYjpwybGx7WQ9Hkb45FhjtsymkwiRRbGJ1SZQ==",
"version": "3.3.9",
"resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.9.tgz",
"integrity": "sha512-xwnSxWl8nZtBl/AFJCOn9pG7s5CYUYdZxmmukv+fAHLcBIHM36dImfpQg3WfShZXeArkWlf6QRw24Klcsv8a5A==",
"dev": true,
"requires": {
"chalk": "2.4.2",
@ -8396,13 +8378,14 @@
}
},
"webpack-dev-middleware": {
"version": "3.7.0",
"resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.0.tgz",
"integrity": "sha512-qvDesR1QZRIAZHOE3iQ4CXLZZSQ1lAUsSpnQmlB1PBfoN/xdRjmge3Dok0W4IdaVLJOGJy3sGI4sZHwjRU0PCA==",
"version": "3.7.1",
"resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.1.tgz",
"integrity": "sha512-5MWu9SH1z3hY7oHOV6Kbkz5x7hXbxK56mGHNqHTe6d+ewxOwKUxoUJBs7QIaJb33lPjl9bJZ3X0vCoooUzC36A==",
"dev": true,
"requires": {
"memory-fs": "^0.4.1",
"mime": "^2.4.2",
"mime": "^2.4.4",
"mkdirp": "^0.5.1",
"range-parser": "^1.2.1",
"webpack-log": "^2.0.0"
},
@ -8416,14 +8399,14 @@
}
},
"webpack-dev-server": {
"version": "3.8.0",
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.8.0.tgz",
"integrity": "sha512-Hs8K9yI6pyMvGkaPTeTonhD6JXVsigXDApYk9JLW4M7viVBspQvb1WdAcWxqtmttxNW4zf2UFLsLNe0y87pIGQ==",
"version": "3.8.1",
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.8.1.tgz",
"integrity": "sha512-9F5DnfFA9bsrhpUCAfQic/AXBVHvq+3gQS+x6Zj0yc1fVVE0erKh2MV4IV12TBewuTrYeeTIRwCH9qLMvdNvTw==",
"dev": true,
"requires": {
"ansi-html": "0.0.7",
"bonjour": "^3.5.0",
"chokidar": "^2.1.6",
"chokidar": "^2.1.8",
"compression": "^1.7.4",
"connect-history-api-fallback": "^1.6.0",
"debug": "^4.1.1",
@ -8434,23 +8417,23 @@
"import-local": "^2.0.0",
"internal-ip": "^4.3.0",
"ip": "^1.1.5",
"is-absolute-url": "^3.0.0",
"is-absolute-url": "^3.0.2",
"killable": "^1.0.1",
"loglevel": "^1.6.3",
"loglevel": "^1.6.4",
"opn": "^5.5.0",
"p-retry": "^3.0.1",
"portfinder": "^1.0.21",
"portfinder": "^1.0.24",
"schema-utils": "^1.0.0",
"selfsigned": "^1.10.4",
"selfsigned": "^1.10.6",
"semver": "^6.3.0",
"serve-index": "^1.9.1",
"sockjs": "0.3.19",
"sockjs-client": "1.3.0",
"sockjs-client": "1.4.0",
"spdy": "^4.0.1",
"strip-ansi": "^3.0.1",
"supports-color": "^6.1.0",
"url": "^0.11.0",
"webpack-dev-middleware": "^3.7.0",
"webpack-dev-middleware": "^3.7.1",
"webpack-log": "^2.0.0",
"ws": "^6.2.1",
"yargs": "12.0.5"

20
package.json

@ -38,20 +38,20 @@
"npm-run-all": "^4.1.5",
"sass-loader": "^8.0.0",
"style-loader": "^1.0.0",
"ts-loader": "^6.0.4",
"ts-node": "^8.3.0",
"typescript": "^3.6.2",
"webpack": "^4.39.3",
"webpack-cli": "^3.3.7",
"webpack-dev-server": "^3.8.0"
"ts-loader": "^6.1.2",
"ts-node": "^8.4.1",
"typescript": "^3.6.3",
"webpack": "^4.40.2",
"webpack-cli": "^3.3.9",
"webpack-dev-server": "^3.8.1"
},
"dependencies": {
"@fortawesome/fontawesome-common-types": "^0.2.22",
"@fortawesome/fontawesome-svg-core": "^1.2.22",
"@fortawesome/free-solid-svg-icons": "^5.10.2",
"@fortawesome/fontawesome-common-types": "^0.2.24",
"@fortawesome/fontawesome-svg-core": "^1.2.24",
"@fortawesome/free-solid-svg-icons": "^5.11.1",
"@fortawesome/react-fontawesome": "^0.1.4",
"classnames": "^2.2.6",
"history": "^4.9.0",
"history": "^4.10.1",
"lodash": "^4.17.15",
"normalizr": "^3.4.1",
"react": "^16.9.0",

11
src/actions/authentication.ts

@ -9,6 +9,10 @@ import { userSchema } from 'src/store/schemas'
import { REQUEST_KEYS } from 'src/constants'
import { AppThunkAction, Entity } from 'src/types'
export interface SetCheckedAction extends Action {
type: 'AUTHENTICATION_SET_CHECKED'
}
export interface SetAuthenticatedAction extends Action {
type: 'AUTHENTICATION_SET_AUTHENTICATED'
payload: boolean
@ -19,7 +23,11 @@ export interface SetUserAction extends Action {
payload: string
}
export type AuthenticationActions = SetAuthenticatedAction | SetUserAction
export type AuthenticationActions = SetCheckedAction | SetAuthenticatedAction | SetUserAction
export const setChecked = (): SetCheckedAction => ({
type: 'AUTHENTICATION_SET_CHECKED',
})
export const setAuthenticated = (authenticated: boolean): SetAuthenticatedAction => ({
type: 'AUTHENTICATION_SET_AUTHENTICATED',
@ -47,6 +55,7 @@ export const fetchSelf = (): AppThunkAction => async dispatch => {
dispatch(finishRequest(REQUEST_KEYS.FETCH_GROUP_AVAILABILITY, true))
} catch (err) {
dispatch(setAuthenticated(false))
dispatch(finishRequest(REQUEST_KEYS.FETCH_GROUP_AVAILABILITY, false))
throw err
}

12
src/components/app/app.scss

@ -34,7 +34,7 @@ $body-size: 14px;
div#main-menu {
background-color: $primary;
border-left: 2px solid $purple;
border-left: 1px solid $grey-lighter;
bottom: 0;
display: flex;
flex-direction: column;
@ -59,8 +59,11 @@ div.centered-content {
width: 80%;
div.centered-content-icon {
border-radius: 100px;
margin: auto;
margin-top: -20px;
text-align: center;
width: 3rem;
}
}
@ -75,3 +78,10 @@ div#navigation {
footer {
padding: $size-normal;
}
div.group-list-item {
background-color: $white;
border-radius: 15px;
margin: 10px 0px;
padding: 20px;
}

5
src/components/app/app.tsx

@ -25,15 +25,18 @@ interface Props {
collapsed: boolean
fetching: boolean
fetchSelf: () => void
setChecked: () => void
}
const App: FC<Props> = ({ collapsed, fetching, fetchSelf }) => {
const App: FC<Props> = ({ collapsed, fetching, fetchSelf, setChecked }) => {
const mainMenuWidth = 275
const mainColumnMargin = collapsed ? 0 : mainMenuWidth
useEffect(() => {
if (localStorage.getItem(LOCAL_STORAGE_ACCESS_TOKEN_KEY)) {
fetchSelf()
} else {
setChecked()
}
}, [])

7
src/components/app/index.ts

@ -1,6 +1,6 @@
import { connect } from 'react-redux'
import { fetchSelf } from 'src/actions/authentication'
import { fetchSelf, setChecked } from 'src/actions/authentication'
import { getFetching } from 'src/selectors'
import { getCollapsed } from 'src/selectors/menu'
@ -16,7 +16,10 @@ const mapStateToProps = (state: AppState) => ({
const mapDispatchToProps = (dispatch: AppThunkDispatch) => ({
fetchSelf: () => {
dispatch(fetchSelf())
}
},
setChecked: () => {
dispatch(setChecked())
}
})
export default connect(

44
src/components/create-group-step/create-group-step.tsx

@ -1,22 +1,30 @@
import React, { FC } from 'react'
import noop from 'lodash/noop'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faBuilding, faArrowRight } from '@fortawesome/free-solid-svg-icons'
import { faBuilding, faArrowLeft } from '@fortawesome/free-solid-svg-icons'
import CreateGroupForm from '../create-group-form'
export interface Props {
name: string
registration: string
agree: boolean
next?: (name: string, agree: boolean) => void
name?: string
registration?: string
agree?: boolean
previous?: () => void
next?: (name: string, registration: string, agree: boolean) => void
register: () => void
}
const CreateGroupStep: FC<Props> = ({ name, agree, next = noop }) => (
const CreateGroupStep: FC<Props> = ({
name = '',
registration = '',
agree = false,
previous = noop,
next = noop,
}) => (
<div className="centered-content">
<div className="centered-content-icon">
<span className="icon is-large has-text-primary">
<FontAwesomeIcon icon={faBuilding} size="lg" />
<div className="centered-content-icon has-background-primary">
<span className="icon is-large has-text-white">
<FontAwesomeIcon icon={faBuilding} size="2x" />
</span>
</div>
@ -24,20 +32,22 @@ const CreateGroupStep: FC<Props> = ({ name, agree, next = noop }) => (
<hr />
<nav className="level">
<div className="level-left">
<p className="level-item"></p>
</div>
<div className="level-right">
<div className="level-left">
<p className="level-item">
<button className="button is-success" onClick={() => next(name, agree)}>
<span>Your Account</span>
<button className="button" onClick={() => previous()}>
<span className="icon is-small">
<FontAwesomeIcon icon={faArrowRight} />
<FontAwesomeIcon icon={faArrowLeft} />
</span>
<span>Your Account</span>
</button>
</p>
</div>
<div className="level-right">
<p className="level-item">
<button className="button is-success" onClick={() => next(name, registration, agree)}>Finish</button>
</p>
</div>
</nav>
</div>
)

13
src/components/create-group-step/index.ts

@ -1,4 +1,3 @@
import { Dispatch } from 'redux'
import { connect } from 'react-redux'
import { setFieldNotification } from 'src/actions/forms'
@ -8,7 +7,7 @@ import { getFieldValue } from 'src/selectors/forms'
import { MAX_ID_LENGTH } from 'src/constants'
import { AppState, AppThunkDispatch } from 'src/types'
import CreateGroupStep from './create-group-step'
import CreateGroupStep, { Props } from './create-group-step'
const mapStateToProps = (state: AppState) => ({
name: getFieldValue<string>(state, 'group-name', ''),
@ -16,8 +15,11 @@ const mapStateToProps = (state: AppState) => ({
agree: getFieldValue<boolean>(state, 'group-agree', false),
})
const mapDispatchToProps = (dispatch: AppThunkDispatch) => ({
next: (name: string, agree: boolean) => {
const mapDispatchToProps = (dispatch: AppThunkDispatch, ownProps: Props) => ({
previous: () => {
dispatch(setStep(0))
},
next: (name: string, registration: string, agree: boolean) => {
let invalid = false
if (!name) {
@ -37,8 +39,7 @@ const mapDispatchToProps = (dispatch: AppThunkDispatch) => ({
}
if (invalid) return
dispatch(setStep(1))
if (ownProps.register) ownProps.register()
},
})

27
src/components/create-user-step/create-user-step.tsx

@ -1,7 +1,7 @@
import React, { FC } from 'react'
import noop from 'lodash/noop'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faUser, faArrowLeft } from '@fortawesome/free-solid-svg-icons'
import { faUser, faArrowRight } from '@fortawesome/free-solid-svg-icons'
import CreateUserForm from '../create-user-form'
@ -11,9 +11,7 @@ export interface Props {
email?: string
password?: string
agree?: boolean
previous?: () => void
next?: (userId: string, name: string, email: string, password: string, agree: boolean) => void
register: () => void
}
const CreateUserStep: FC<Props> = ({
@ -22,13 +20,12 @@ const CreateUserStep: FC<Props> = ({
email = '',
password = '',
agree = false,
previous = noop,
next = noop,
}) => (
<div className="centered-content">
<div className="centered-content-icon">
<span className="icon is-large has-text-primary">
<FontAwesomeIcon icon={faUser} size="lg" />
<div className="centered-content-icon has-background-primary">
<span className="icon is-large has-text-white">
<FontAwesomeIcon icon={faUser} size="2x" />
</span>
</div>
@ -37,19 +34,17 @@ const CreateUserStep: FC<Props> = ({
<nav className="level">
<div className="level-left">
<p className="level-item">
<button className="button" onClick={() => previous()}>
<span className="icon is-small">
<FontAwesomeIcon icon={faArrowLeft} />
</span>
<span>Community</span>
</button>
</p>
<p className="level-item"></p>
</div>
<div className="level-right">
<p className="level-item">
<button className="button is-success" onClick={() => next(userId, name, email, password, agree)}>Finish</button>
<button className="button is-success" onClick={() => next(userId, name, email, password, agree)}>
<span>Community</span>
<span className="icon is-small">
<FontAwesomeIcon icon={faArrowRight} />
</span>
</button>
</p>
</div>
</nav>

5
src/components/create-user-step/index.ts

@ -19,9 +19,6 @@ const mapStateToProps = (state: AppState) => ({
})
const mapDispatchToProps = (dispatch: AppThunkDispatch, ownProps: Props) => ({
previous: () => {
dispatch(setStep(0))
},
next: (userId: string, name: string, email: string, password: string, agree: boolean) => {
let invalid = false
@ -64,7 +61,7 @@ const mapDispatchToProps = (dispatch: AppThunkDispatch, ownProps: Props) => ({
}
if (invalid) return
if (ownProps.register) ownProps.register()
dispatch(setStep(1))
},
})

49
src/components/group-list/group-list-item/index.tsx

@ -0,0 +1,49 @@
import React, { FC } from 'react'
import { Link } from 'react-router-dom'
import { Group } from 'src/types'
interface Props {
group: Group
}
const GroupListItem: FC<Props> = ({ group }) => (
<div className="group-list-item">
<Link to={`/c/${group.id}/register`} className="title has-text-primary">{group.name}</Link>
{group.about && <p>{group.about}</p>}
<br /><br />
<nav className="level">
<div className="level-item has-text-centered">
<div>
<p className="heading">Members</p>
<p className="title">{group.members}</p>
</div>
</div>
<div className="level-item has-text-centered">
<div>
<p className="heading">Posts</p>
<p className="title">{group.posts}</p>
</div>
</div>
<div className="level-item has-text-centered">
<div>
<p className="heading has-text-success">Awards</p>
<p className="title">{group.posts}</p>
</div>
</div>
<div className="level-item has-text-centered">
<div>
<p className="heading">Points</p>
<p className="title">{group.points}</p>
</div>
</div>
</nav>
</div>
)
export default GroupListItem

17
src/components/group-list/index.tsx

@ -0,0 +1,17 @@
import React, { FC } from 'react'
import { Group } from 'src/types'
import GroupListItem from './group-list-item'
interface Props {
groups: Group[]
}
const GroupList: FC<Props> = ({ groups }) => (
<div>
{groups.map(group => <GroupListItem group={group} />)}
</div>
)
export default GroupList

8
src/components/pages/directory/directory.tsx

@ -2,12 +2,13 @@ import React, { FC, useEffect } from 'react'
import { Link } from 'react-router-dom'
import { setTitle } from 'src/utils'
import { Entity } from 'src/types'
import { Group } from 'src/types'
import PageHeader from 'src/components/page-header'
import GroupList from 'src/components/group-list'
interface Props {
groups: Entity[]
groups: Group[]
fetchGroups: () => void
}
@ -25,7 +26,10 @@ const Directory: FC<Props> = ({ groups, fetchGroups }) => {
<PageHeader title="Communities" />
<div className="main-content">
<GroupList groups={groups} />
{groups.length === 0 && <p>No Communities</p>}
<br /><br />
<p className="has-text-centered">
<Link className="has-text-primary" to="/register">Create your own Community</Link>

2
src/components/pages/register-group/index.ts

@ -8,7 +8,7 @@ import { AppState, AppThunkDispatch } from 'src/types'
import RegisterGroup, { Props } from './register-group'
const mapStateToProps = (state: AppState, ownProps: Props) => ({
group: getEntity(state, 'group', ownProps.match.params.id),
group: getEntity(state, 'groups', ownProps.match.params.id),
})
const mapDispatchToProps = (dispatch: AppThunkDispatch, ownProps: Props) => ({

11
src/components/pages/register/index.ts

@ -41,17 +41,16 @@ const mapDispatchToProps = (dispatch: AppThunkDispatch, ownProps: Props) => ({
}
try {
const group = await dispatch(createGroup({
name: valueFromForm<string>(form, 'group-name', ''),
registration: valueFromForm<string>(form, 'group-registration', ''),
}))
await dispatch(register({
id: valueFromForm<string>(form, 'user-id', ''),
email: valueFromForm<string>(form, 'user-email', ''),
password: valueFromForm<string>(form, 'password', ''),
name: valueFromForm<string>(form, 'user-name', ''),
group,
}))
await dispatch(createGroup({
name: valueFromForm<string>(form, 'group-name', ''),
registration: valueFromForm<string>(form, 'group-registration', ''),
}))
ownProps.history.push('/self')

8
src/components/pages/register/register.tsx

@ -18,15 +18,15 @@ export interface Props extends RouteComponentProps {
const Register: FC<Props> = ({ stepIndex, form, initForm, register }) => {
const title = () => {
switch (stepIndex) {
case 0: return 'Create a Community'
default: return 'Create Your Account'
case 0: return 'Create Your Account'
default: return 'Create a Community'
}
}
const component = () => {
switch (stepIndex) {
case 0: return <CreateGroupStep />
default: return <CreateUserStep register={() => register(form)} />
case 0: return <CreateUserStep />
default: return <CreateGroupStep register={() => register(form)} />
}
}

5
src/components/pages/self/index.ts

@ -1,6 +1,6 @@
import { connect } from 'react-redux'
import { getAuthenticated, getAuthenticatedUserId } from 'src/selectors/authentication'
import { getAuthenticated, getAuthenticatedUserId, getChecked } from 'src/selectors/authentication'
import { getEntity } from 'src/selectors/entities'
import { AppState } from 'src/types'
@ -8,9 +8,10 @@ import Self from './self'
const mapStateToProps = (state: AppState) => {
const userId = getAuthenticatedUserId(state)
const user = userId ? getEntity(state, 'user', userId) : undefined
const user = userId ? getEntity(state, 'users', userId) : undefined
return {
checked: getChecked(state),
authenticated: getAuthenticated(state),
user,
}

11
src/components/pages/self/self.tsx

@ -7,22 +7,23 @@ import { Entity } from 'src/types'
import PageHeader from 'src/components/page-header'
interface Props extends RouteComponentProps {
checked: boolean
authenticated: boolean
user?: Entity
}
const Self: FC<Props> = ({ authenticated, user, history }) => {
const Self: FC<Props> = ({ checked, authenticated, user, history }) => {
useEffect(() => {
if (!authenticated) history.push('/login')
}, [authenticated])
if (checked && !authenticated) history.push('/login')
}, [checked, authenticated])
useEffect(() => {
if (user) setTitle(user.name as string)
if (user) setTitle(`${user.name} (@${user.id})`)
}, [user])
return (
<div>
<PageHeader title={user ? user.name as string : '?'} />
<PageHeader title={user ? user.name as string : '?'} subtitle={user ? user.id : '?'} />
<div className="main-content">
<p>

17
src/components/user-info/index.ts

@ -1,13 +1,20 @@
import { connect } from 'react-redux'
import { getAuthenticated } from 'src/selectors/authentication'
import { AppState } from 'src/types'
import { getAuthenticated, getAuthenticatedUserId } from 'src/selectors/authentication'
import { getEntity } from 'src/selectors/entities'
import { AppState, User } from 'src/types'
import UserInfo from './user-info'
const mapStateToProps = (state: AppState) => ({
authenticated: getAuthenticated(state),
})
const mapStateToProps = (state: AppState) => {
const userId = getAuthenticatedUserId(state)
const user = userId ? getEntity<User>(state, 'users', userId) : undefined
return {
authenticated: getAuthenticated(state),
user,
}
}
export default connect(
mapStateToProps

56
src/components/user-info/user-info.tsx

@ -14,16 +14,40 @@ const UserInfo: FC<Props> = ({ authenticated, user }) => {
const hasAvatar = authenticated && user && user.imageUrl
const imageUrl = hasAvatar ? user!.imageUrl : undefined
return (
<article id="user-info" className="media has-background-black">
{hasAvatar &&
<figure className="media-left">
<p className="image is-64x64">
<img src={imageUrl} />
</p>
</figure>
}
const name = () => {
if (!user) return <span></span>
if (user.name) {
return (
<>
<span className="is-size-4 has-text-white">{user.name}</span>
&nbsp;&nbsp;
<Link to="/self" className="is-size-6 has-text-white-ter">@{user.id}</Link>
</>
)
}
return <Link to="/self" className="is-size-4 has-text-white-ter">@{user.id}</Link>
}
const content = () => {
if (authenticated && user) {
return (
<div className="media-content">
<div className="content">
<div>
{name()}
<br />
{user.group &&
<Link to={`/c/${user.group.id}`} className="is-size-5 has-text-success">{user.group.name}</Link>
}
</div>
</div>
</div>
)
}
return (
<div className="media-content">
<div className="content">
<div className="has-text-centered">
@ -35,6 +59,20 @@ const UserInfo: FC<Props> = ({ authenticated, user }) => {
</div>
</div>
</div>
)
}
return (
<article id="user-info" className="media has-background-black">
{hasAvatar &&
<figure className="media-left">
<p className="image is-64x64">
<img src={imageUrl} />
</p>
</figure>
}
{content()}
</article>
)
}

7
src/reducers/authentication.ts

@ -4,16 +4,23 @@ import { AuthenticationActions } from '../actions/authentication'
import { AuthenticationState } from '../types'
const initialState: AuthenticationState = {
checked: false,
authenticated: false,
userId: undefined,
}
const reducer: Reducer<AuthenticationState, AuthenticationActions> = (state = initialState, action) => {
switch (action.type) {
case 'AUTHENTICATION_SET_CHECKED':
return {
...state,
checked: true,
}
case 'AUTHENTICATION_SET_AUTHENTICATED':
return {
...state,
authenticated: action.payload,
checked: true,
}
case 'AUTHENTICATION_SET_USER':
return {

1
src/selectors/authentication.ts

@ -1,4 +1,5 @@
import { AppState } from '../types'
export const getChecked = (state: AppState) => state.authentication.checked
export const getAuthenticated = (state: AppState) => state.authentication.authenticated
export const getAuthenticatedUserId = (state: AppState) => state.authentication.userId

4
src/selectors/directory.ts

@ -3,13 +3,13 @@ import { createSelector } from 'reselect'
import { groupSchema } from '../store/schemas'
import { getEntityStore } from './entities'
import { AppState, Entity } from '../types'
import { AppState, Group } from '../types'
export const getGroupIds = (state: AppState) => state.directory.groups
export const getGroups = createSelector(
[getEntityStore, getGroupIds],
(store, groups) => {
return denormalize(groups, [groupSchema], store) as Entity[]
return denormalize(groups, [groupSchema], store) as Group[]
}
)

6
src/selectors/entities.ts

@ -1,10 +1,10 @@
import { AppState } from '../types'
import { AppState, Entity, EntityTypes } from '../types'
export const getEntityStore = (state: AppState) => state.entities
export const getEntity = (state: AppState, type: string, id: string) => {
export const getEntity = <T extends Entity = Entity>(state: AppState, type: EntityTypes, id: string) => {
const store = getEntityStore(state)
const collection = store[type]
return collection ? collection[id] : undefined
return collection ? collection[id] as T : undefined
}

2
src/types/entities.ts

@ -1,3 +1,5 @@
export type EntityTypes = 'users' | 'groups'
export interface Entity {
[key: string]: string | number | boolean | object | any[]
id: string

29
src/types/index.ts

@ -15,33 +15,8 @@ export interface ClassDictionary {
[name: string]: boolean
}
export {
Entity,
Group,
User,
EntityCollection,
EntityStore,
} from './entities'
export {
NotificationType,
FormValue,
FormNotification,
APIRequest,
APIRequestCollection,
Notification,
AuthenticationState,
MenuState,
FormField,
Form,
FormsState,
DirectoryState,
RequestsState,
NotificationsState,
EntitiesState,
RegistrationState,
AppState,
} from './store'
export * from './entities'
export * from './store'
export type AppThunkDispatch = ThunkDispatch<AppState, void, AnyAction>
export type AppThunkAction<T = void> = ThunkAction<Promise<T>, AppState, void, AnyAction>

1
src/types/store.ts

@ -29,6 +29,7 @@ export interface Notification {
}
export interface AuthenticationState {
checked: boolean
authenticated: boolean
userId?: string
}

Loading…
Cancel
Save