cetirizine

An experimental matrix client written in reactjs utilizing tailwind and storybook
git clone git://archive.git.mtrnord.blog/MTRNord/cetirizine.git
Log | Files | Refs | README | LICENSE

commit cfddeab63e1ad7f7becd2f4d80e3777774a34652
parent 0466f5d4344d41f92f4bb8bb471c60bc306c6a2c
Author: MTRNord <mtrnord1@gmail.com>
Date:   Sat, 22 Apr 2023 18:05:02 +0200

chore: cleanup redux

Diffstat:
Mindex.html | 5+++++
Mpackage-lock.json | 195+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
Mpackage.json | 4+++-
Msrc/app/api/api.ts | 118++++++++++++++++++++++++++++++++++---------------------------------------------
Msrc/app/api/reducers.ts | 41++++++++++++-----------------------------
Msrc/components/button/button.tsx | 7++++---
Msrc/components/input/basic/input.tsx | 8++++----
Msrc/components/login/login.tsx | 8++++----
Asrc/components/roomList/roomList.stories.tsx | 35+++++++++++++++++++++++++++++++++++
Asrc/components/roomList/roomList.tsx | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/main.tsx | 3+++
11 files changed, 328 insertions(+), 157 deletions(-)

diff --git a/index.html b/index.html @@ -8,6 +8,11 @@ content="A Matrix Client" /> <title>Matrix</title> + <script> + if (global === undefined) { + var global = window; + } + </script> </head> <body> <noscript>You need to enable JavaScript to run this app.</noscript> diff --git a/package-lock.json b/package-lock.json @@ -17,9 +17,11 @@ "@types/node": "^17.0.45", "@types/react": "^18.0.37", "@types/react-dom": "^18.0.11", - "axios": "^1.3.5", + "dompurify": "^3.0.2", "lexical": "^0.10.0", "lucide-react": "^0.171.0", + "matrix-js-sdk": "^24.1.0", + "olm": "https://packages.matrix.org/npm/olm/olm-3.2.1.tgz", "react": "^18.2.0", "react-dom": "^18.2.0", "react-redux": "^8.0.5", @@ -3050,6 +3052,14 @@ "yjs": ">=13.5.22" } }, + "node_modules/@matrix-org/matrix-sdk-crypto-js": { + "version": "0.1.0-alpha.7", + "resolved": "https://registry.npmjs.org/@matrix-org/matrix-sdk-crypto-js/-/matrix-sdk-crypto-js-0.1.0-alpha.7.tgz", + "integrity": "sha512-sQEG9cSfNji5NYBf5h7j5IxYVO0dwtAKoetaVyR+LhIXz/Su7zyEE3EwlAWAeJOFdAV/vZ5LTNyh39xADuNlTg==", + "engines": { + "node": ">= 10" + } + }, "node_modules/@mdx-js/react": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-2.3.0.tgz", @@ -5556,6 +5566,11 @@ "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", "dev": true }, + "node_modules/@types/events": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", + "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==" + }, "node_modules/@types/express": { "version": "4.17.17", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", @@ -5765,6 +5780,11 @@ "@types/react": "*" } }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==" + }, "node_modules/@types/scheduler": { "version": "0.16.3", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", @@ -6139,6 +6159,11 @@ "ajv": "^6.9.1" } }, + "node_modules/another-json": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/another-json/-/another-json-0.2.0.tgz", + "integrity": "sha512-/Ndrl68UQLhnCdsAzEXLMFuOR546o2qbYRqCglaNHbjXrwG1ayTcdwr3zkSGOGtGXDyR5X9nCFfnyG2AFJIsqg==" + }, "node_modules/ansi-align": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", @@ -6301,7 +6326,8 @@ "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true }, "node_modules/autoprefixer": { "version": "10.4.14", @@ -6356,16 +6382,6 @@ "node": ">=4" } }, - "node_modules/axios": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.3.6.tgz", - "integrity": "sha512-PEcdkk7JcdPiMDkvM4K6ZBRYq9keuVJsToxm2zQIM70Qqo2WHTdJZMXcG9X+RmRp2VPNUQC8W1RAGbgt6b1yMg==", - "dependencies": { - "follow-redirects": "^1.15.0", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - } - }, "node_modules/babel-core": { "version": "7.0.0-bridge.0", "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz", @@ -6436,6 +6452,11 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/base-x": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-4.0.0.tgz", + "integrity": "sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw==" + }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -6750,6 +6771,14 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/bs58": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-5.0.0.tgz", + "integrity": "sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==", + "dependencies": { + "base-x": "^4.0.0" + } + }, "node_modules/bser": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", @@ -7131,6 +7160,7 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, "dependencies": { "delayed-stream": "~1.0.0" }, @@ -7292,7 +7322,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "dev": true, "engines": { "node": ">= 0.6" } @@ -7679,6 +7708,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, "engines": { "node": ">=0.4.0" } @@ -7811,6 +7841,11 @@ "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==" }, + "node_modules/dompurify": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.0.2.tgz", + "integrity": "sha512-B8c6JdiEpxAKnd8Dm++QQxJL4lfuc757scZtcapj6qjTjrQzyq5iAyznLKVvK+77eYNiFblHBlt7MM0fOeqoKw==" + }, "node_modules/dotenv": { "version": "16.0.3", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", @@ -8204,8 +8239,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true, - "peer": true, "engines": { "node": ">=0.8.x" } @@ -8579,25 +8612,6 @@ "node": ">=0.4.0" } }, - "node_modules/follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, "node_modules/for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -8619,19 +8633,6 @@ "node": ">=8.0.0" } }, - "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -10622,6 +10623,18 @@ "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", "dev": true }, + "node_modules/loglevel": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.8.1.tgz", + "integrity": "sha512-tCRIJM51SHjAayKwC+QAg8hT8vg6z7GSgLJKGvzuPb1Wc+hLzqtuVLxp6/HzSPOozuK+8ErAhy7U/sVzw8Dgfg==", + "engines": { + "node": ">= 0.6.0" + }, + "funding": { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/loglevel" + } + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -10719,6 +10732,42 @@ "react": ">= 0.14.0" } }, + "node_modules/matrix-events-sdk": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/matrix-events-sdk/-/matrix-events-sdk-0.0.1.tgz", + "integrity": "sha512-1QEOsXO+bhyCroIe2/A5OwaxHvBm7EsSQ46DEDn8RBIfQwN5HWBpFvyWWR4QY0KHPPnnJdI99wgRiAl7Ad5qaA==" + }, + "node_modules/matrix-js-sdk": { + "version": "24.1.0", + "resolved": "https://registry.npmjs.org/matrix-js-sdk/-/matrix-js-sdk-24.1.0.tgz", + "integrity": "sha512-xEx2ZoNsS56dwgqLJ3rIv2SUpFxdQLrLKmJCpMatMUKCAg+NGuZfpQ3QXblIbGaqFNQZCH7fC7S48AeTMZp1Jw==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "@matrix-org/matrix-sdk-crypto-js": "^0.1.0-alpha.5", + "another-json": "^0.2.0", + "bs58": "^5.0.0", + "content-type": "^1.0.4", + "loglevel": "^1.7.1", + "matrix-events-sdk": "0.0.1", + "matrix-widget-api": "^1.3.1", + "p-retry": "4", + "sdp-transform": "^2.14.1", + "unhomoglyph": "^1.0.6", + "uuid": "9" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/matrix-widget-api": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/matrix-widget-api/-/matrix-widget-api-1.3.1.tgz", + "integrity": "sha512-+rN6vGvnXm+fn0uq9r2KWSL/aPtehD6ObC50jYmUcEfgo8CUpf9eUurmjbRlwZkWq3XHXFuKQBUCI9UzqWg37Q==", + "dependencies": { + "@types/events": "^3.0.0", + "events": "^3.2.0" + } + }, "node_modules/mdast-util-definitions": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-4.0.0.tgz", @@ -10819,6 +10868,7 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, "engines": { "node": ">= 0.6" } @@ -10827,6 +10877,7 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, "dependencies": { "mime-db": "1.52.0" }, @@ -11199,6 +11250,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/olm": { + "version": "3.2.1", + "resolved": "https://packages.matrix.org/npm/olm/olm-3.2.1.tgz", + "integrity": "sha512-B87bTpGIGieuV2FNauChjjQtVltwTGagQFoHm+3Dcse4amKAAGJB/I54dnP/JtbHZ+RYVoApM2OQ46Z4VH6eNg==", + "license": "Apache-2.0" + }, "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", @@ -11323,6 +11380,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -11899,7 +11968,8 @@ "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true }, "node_modules/pump": { "version": "3.0.0", @@ -12707,6 +12777,14 @@ "node": ">=12" } }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "engines": { + "node": ">= 4" + } + }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -12918,6 +12996,14 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/sdp-transform": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/sdp-transform/-/sdp-transform-2.14.1.tgz", + "integrity": "sha512-RjZyX3nVwJyCuTo5tGPx+PZWkDMCg7oOLpSlhjDdZfwUoNqG1mM8nyj31IGHyaPWXhjbP7cdK3qZ2bmkJ1GzRw==", + "bin": { + "sdp-verify": "checker.js" + } + }, "node_modules/semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -14235,6 +14321,11 @@ "integrity": "sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==", "dev": true }, + "node_modules/unhomoglyph": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/unhomoglyph/-/unhomoglyph-1.0.6.tgz", + "integrity": "sha512-7uvcWI3hWshSADBu4JpnyYbTVc7YlhF5GDW/oPD5AxIxl34k4wXR3WDkPnzLxkN32LiTCTKMQLtKVZiwki3zGg==" + }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", @@ -14466,6 +14557,14 @@ "node": ">= 0.4.0" } }, + "node_modules/uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/uuid-browser": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/uuid-browser/-/uuid-browser-3.1.0.tgz", diff --git a/package.json b/package.json @@ -13,9 +13,11 @@ "@types/node": "^17.0.45", "@types/react": "^18.0.37", "@types/react-dom": "^18.0.11", - "axios": "^1.3.5", + "dompurify": "^3.0.2", "lexical": "^0.10.0", "lucide-react": "^0.171.0", + "matrix-js-sdk": "^24.1.0", + "olm": "https://packages.matrix.org/npm/olm/olm-3.2.1.tgz", "react": "^18.2.0", "react-dom": "^18.2.0", "react-redux": "^8.0.5", diff --git a/src/app/api/api.ts b/src/app/api/api.ts @@ -1,84 +1,65 @@ -import axios, { AxiosResponse } from "axios"; -import { all, call, fork, put, select, takeEvery } from "redux-saga/effects"; -import { RootState } from "../store"; -import { LOGIN_FAILURE, LOGIN_REQUEST, LOGIN_SUCCESS } from "./reducers"; +import { all, call, fork, put, takeEvery } from "redux-saga/effects"; +import { LOGIN_REQUEST_ACTION, LOGIN_SUCCESS_ACTION, LOGIN, LOGIN_ACTION, LOGIN_FAILURE_ACTION } from "./reducers"; +import { IndexedDBCryptoStore, IndexedDBStore, MatrixClient, MemoryStore, createClient, setCryptoStoreFactory } from "matrix-js-sdk"; -export const getAccessToken = (state: RootState) => state.api.accessToken; -export const getBaseUrl = (state: RootState) => state.api.baseUrl; - -export enum ApiActions { - LOGIN = "LOGIN", - - SYNC = "SYNC", - SYNC_REQUEST = "SYNC_REQUEST", - SYNC_SUCCESS = "SYNC_SUCCESS", - SYNC_FAILURE = "SYNC_FAILURE", -} - -function sync(baseUrl: string, accessToken: string): Promise<AxiosResponse<any, any>> { - return axios.get("/sync", { - params: {}, - baseURL: baseUrl, - headers: { - Authorization: `Bearer ${accessToken}`, - }, - }); -} - -function login(baseUrl: string): Promise<AxiosResponse<any, any>> { - return axios.get("/login", { - params: {}, - baseURL: baseUrl, - }); -} - -function* onSyncSaga(): any { - try { - yield put({ type: ApiActions.SYNC_REQUEST }); - const accessToken: string = yield select(getAccessToken); - const baseUrl: string = yield select(getBaseUrl); - const response = yield call(sync, baseUrl, accessToken); - const data = response.data; - yield put({ type: ApiActions.SYNC_SUCCESS, data }); - } catch (e) { - yield put({ - type: ApiActions.SYNC_FAILURE, - payload: (e as any).toString(), - }); - } +function login(baseUrl: string, userId: string, password: string): Promise<MatrixClient> { + return initMatrixClient(baseUrl, userId, undefined, password); } -function* onLoginSaga(): any { +function* onLoginSaga(action: LOGIN): any { try { - yield put({ type: LOGIN_REQUEST }); - const baseUrl: string = yield select(getBaseUrl); - if (!baseUrl.startsWith("https://")) { - yield put({ - type: LOGIN_FAILURE, - payload: "Homeserver url must start with https://", - }); + yield put(LOGIN_REQUEST_ACTION()); + if (!action.baseUrl.startsWith("https://")) { + yield put(LOGIN_FAILURE_ACTION("Homeserver url must start with https://")); return; } - const response = yield call(login, baseUrl); - const data = response.data; - yield put({ type: LOGIN_SUCCESS, data }); + const client = yield call(login, action.baseUrl, action.username, action.password); + yield put(LOGIN_SUCCESS_ACTION(client)); } catch (e) { - yield put({ - type: LOGIN_FAILURE, - payload: (e as any).toString(), - }); + yield put(LOGIN_FAILURE_ACTION((e as any).toString())); } } function* watchLoginSaga() { - yield takeEvery(ApiActions.LOGIN, onLoginSaga); -} - -function* syncLoginSaga() { - yield takeEvery(ApiActions.SYNC, onSyncSaga); + yield takeEvery<LOGIN>(LOGIN_ACTION, onLoginSaga); } export function* apiSagas() { - yield all([fork(watchLoginSaga), fork(syncLoginSaga)]); + yield all([fork(watchLoginSaga)]); } + +async function initMatrixClient(baseURL: string, userId: string, accessToken?: string, password?: string): Promise<MatrixClient> { + // just *accessing* indexedDB throws an exception in firefox with indexeddb disabled. + let indexedDB: IDBFactory | undefined; + try { + indexedDB = global.indexedDB; + } catch (e) { } + + // if our browser (appears to) support indexeddb, use an indexeddb crypto store. + let store = new MemoryStore({ localStorage: window.localStorage }); + if (indexedDB) { + setCryptoStoreFactory(() => new IndexedDBCryptoStore(indexedDB!, "matrix-js-sdk:crypto")); + store = new IndexedDBStore({ indexedDB: indexedDB, localStorage: window.localStorage }); + await store.startup(); + } + + const matrixClient = createClient({ + baseUrl: baseURL, + accessToken: accessToken, + userId: accessToken ? userId : undefined, + useAuthorizationHeader: true, + store + }); + + if (!accessToken && !password) { + throw Error("Missing password and accessToken. Unable to proceed") + } + + if (!accessToken) { + await matrixClient.loginWithPassword(userId, password!!); + } + + await matrixClient.initCrypto(); + return matrixClient +} +\ No newline at end of file diff --git a/src/app/api/reducers.ts b/src/app/api/reducers.ts @@ -1,51 +1,34 @@ -import { createAction, createReducer } from "@reduxjs/toolkit"; +import { Action, createAction, createReducer } from "@reduxjs/toolkit"; import { RootState } from "../store"; - -interface ApiState { - accessToken?: string - baseUrl?: string -} - -export const setAccessToken = createAction<string>('api/setAccessToken'); -export const setBaseUrl = createAction<string>('api/setBaseUrl'); - -const initialApiState: ApiState = { accessToken: undefined, baseUrl: undefined }; - - -export const apiDataReducer = createReducer(initialApiState, (builder) => { - builder - .addCase(setAccessToken, (state, action) => { - state.accessToken = action.payload; - }) - .addCase(setBaseUrl, (state, action) => { - // TODO: Do we well-known here? - state.baseUrl = action.payload; - }) -}); +import { MatrixClient } from "matrix-js-sdk"; interface ApiLoginStatus { loginPending: boolean error?: string } -export const LOGIN_REQUEST = createAction('api/LOGIN_REQUEST'); -export const LOGIN_SUCCESS = createAction<any>('api/LOGIN_SUCCESS'); -export const LOGIN_FAILURE = createAction<string>('api/LOGIN_FAILURE'); +export const LOGIN_ACTION = "api/LOGIN"; +export const LOGIN_REQUEST_ACTION = createAction('api/LOGIN_REQUEST'); +export const LOGIN_SUCCESS_ACTION = createAction<MatrixClient>('api/LOGIN_SUCCESS'); +export const LOGIN_FAILURE_ACTION = createAction<string>('api/LOGIN_FAILURE'); + +export interface LOGIN extends Action { type: typeof LOGIN_ACTION, baseUrl: string, username: string, password: string }; + const initialLoginState: ApiLoginStatus = { loginPending: false, error: undefined }; export const apiLoginReducer = createReducer(initialLoginState, (builder) => { builder - .addCase(LOGIN_REQUEST, (state, _) => { + .addCase(LOGIN_REQUEST_ACTION, (state, _) => { state.loginPending = true; state.error = undefined; }) // @ts-ignore: Somehow this state is causing issues here since its written but not read. TS6133 - .addCase(LOGIN_SUCCESS, (state, _) => { + .addCase(LOGIN_SUCCESS_ACTION, (state, _) => { state = initialLoginState; }) - .addCase(LOGIN_FAILURE, (state, action) => { + .addCase(LOGIN_FAILURE_ACTION, (state, action) => { state.loginPending = false; state.error = action.payload }) diff --git a/src/components/button/button.tsx b/src/components/button/button.tsx @@ -1,3 +1,4 @@ +import { memo } from "react"; import "./button.scss"; type ButtonProps = { @@ -19,7 +20,7 @@ type ButtonProps = { children: string }; -export default function Button({ type = "button", style = "primary", onClick, children }: ButtonProps) { +export default memo(function Button({ type = "button", style = "primary", onClick, children }: ButtonProps) { if (style === "secondary") { return <button onClick={onClick} className="button bg-orange-400 hover:bg-orange-500 ease-out duration-150" type={type}>{children}</button>; } else if (style === "abort") { @@ -27,4 +28,4 @@ export default function Button({ type = "button", style = "primary", onClick, ch } else { return <button onClick={onClick} className="button bg-green-400 hover:bg-green-500 ease-out duration-150" type={type}>{children}</button>; } -} -\ No newline at end of file +}); +\ No newline at end of file diff --git a/src/components/input/basic/input.tsx b/src/components/input/basic/input.tsx @@ -1,4 +1,4 @@ -import { ChangeEvent } from 'react'; +import { ChangeEvent, memo } from 'react'; type InputProps = { /** @@ -23,7 +23,7 @@ type InputProps = { onChange: (e: ChangeEvent<HTMLInputElement>) => void; }; -export default function Input({ placeholder, password = false, autoFocus = false, value, onChange }: InputProps) { +export default memo(function Input({ placeholder, password = false, autoFocus = false, value, onChange }: InputProps) { return ( <input className='form-input rounded-lg' @@ -34,4 +34,4 @@ export default function Input({ placeholder, password = false, autoFocus = false onChange={onChange} /> ); -} -\ No newline at end of file +}); +\ No newline at end of file diff --git a/src/components/login/login.tsx b/src/components/login/login.tsx @@ -1,11 +1,11 @@ import { useState } from 'react'; -import { ApiActions } from '../../app/api/api'; -import { getLoginError, setBaseUrl } from '../../app/api/reducers'; +import { getLoginError } from '../../app/api/reducers'; import { useAppDispatch, useAppSelector } from '../../app/hooks'; import { RootState } from '../../app/store'; import Button from '../button/button'; import Header from '../header/header'; import Input from '../input/basic/input'; +import { LOGIN_ACTION } from '../../app/api/reducers'; export function Login() { const loginError = useAppSelector((state: RootState) => getLoginError(state)); @@ -22,7 +22,7 @@ export function Login() { value={homeserver} autoFocus={true} placeholder="Homeserver" - onChange={e => { setHomeserver(e.target.value); dispatch(setBaseUrl(e.target.value)) }} + onChange={e => setHomeserver(e.target.value)} /> <Input value={username} @@ -38,7 +38,7 @@ export function Login() { <Button style="primary" type="button" - onClick={() => dispatch({ type: ApiActions.LOGIN })} + onClick={() => dispatch({ type: LOGIN_ACTION, baseUrl: homeserver, username: username, password: password })} > Login </Button> diff --git a/src/components/roomList/roomList.stories.tsx b/src/components/roomList/roomList.stories.tsx @@ -0,0 +1,34 @@ +import { Meta, StoryObj } from '@storybook/react'; +import RoomList from './roomList'; +import { BADGE } from '@geometricpanda/storybook-addon-badges'; + +const meta: Meta<typeof RoomList> = { + title: 'Chat/RoomList', + tags: ['autodocs'], + component: RoomList, + parameters: { + badges: [BADGE.EXPERIMENTAL] + }, + argTypes: { + sections: { + required: true, + defaultValue: [], + name: "Sections", + description: "The Sections available", + }, + rooms: { + required: true, + defaultValue: [], + name: "Rooms", + description: "Rooms outside of any Sections", + }, + } +}; + +export default meta; +type Story = StoryObj<typeof RoomList>; + +export const RootList: Story = { + args: { + } +}; +\ No newline at end of file diff --git a/src/components/roomList/roomList.tsx b/src/components/roomList/roomList.tsx @@ -0,0 +1,60 @@ +type Room = { + /** + * The URL of the Avatar image + */ + avatarUrl?: string + /** + * The displayname of the room list item + */ + displayname: string + /** + * Wether it is a DM or not + */ + dm: boolean + /** + * Wether the user is online. Only used if dm is true. + */ + online: boolean + /** + * Wether the current room is selected + */ + active: boolean + /** + * The roomid of the Room + */ + roomID: string +}; + +type Section = { + /** + * Section Name. Can be a Space or a Tag + */ + sectionName: string + /** + * The Rooms within the Section + */ + rooms: Room[] + /** + * The Subsections of the Section + */ + subsections: Section[] +} + +type RoomListProps = { + /** + * The Sections available + */ + sections: Section[] + /** + * Rooms outside of any Sections + */ + rooms: Room[] +}; + +export default function RoomList({ sections, rooms }: RoomListProps) { + return ( + <div> + + </div> + ); +} +\ No newline at end of file diff --git a/src/main.tsx b/src/main.tsx @@ -8,6 +8,9 @@ import './index.scss'; const container = document.getElementById('root')!; const root = createRoot(container); +// js-sdk helper +window.Olm = await import("olm"); + root.render( <React.StrictMode> <Provider store={store}>