Convert js files in `client/src` to Typescript
Gitlab: #30
Change-Id: I679b8b0f30445a872d152ae93ecad5ff6c9a259f
diff --git a/client/i18next-parser.config.js b/client/i18next-parser.config.js
index 2f9d13c..1e18e78 100644
--- a/client/i18next-parser.config.js
+++ b/client/i18next-parser.config.js
@@ -1,5 +1,5 @@
export default {
locales: ['fr', 'en'],
output: 'public/locale/$LOCALE/$NAMESPACE.json',
- input: ['src/**/*.{js,jsx}'],
+ input: ['src/**/*.{ts,tsx,js,jsx}'],
};
diff --git a/client/src/App.test.js b/client/src/App.test.tsx
similarity index 100%
rename from client/src/App.test.js
rename to client/src/App.test.tsx
diff --git a/client/src/App.js b/client/src/App.tsx
similarity index 91%
rename from client/src/App.js
rename to client/src/App.tsx
index 7cec1ee..0893dbd 100644
--- a/client/src/App.js
+++ b/client/src/App.tsx
@@ -23,9 +23,7 @@
// import { useSelector, useDispatch } from 'react-redux'
// import { useAppSelector, useAppDispatch } from '../redux/hooks'
-const Home = (props) => {
- console.log(`home ${props}`);
-
+const Home = () => {
return <Navigate to="/account" />;
};
@@ -57,7 +55,7 @@
<Routes>
<Route path="/setup" element={<ServerSetup />} />
<Route path="/" element={<Navigate to="/setup" replace />} />
- <Route index path="*" element={<Navigate to="/setup" replace />} />
+ <Route path="*" element={<Navigate to="/setup" replace />} />
</Routes>
);
}
@@ -68,7 +66,7 @@
<Route path="/account">
<Route index element={<AccountSelection />} />
<Route path=":accountId">
- <Route index path="*" element={<JamiMessenger />} />
+ <Route path="*" element={<JamiMessenger />} />
<Route path="settings" element={<AccountSettings />} />
</Route>
</Route>
@@ -78,7 +76,7 @@
{/* <Route path="/Contacts" element={<ContactList />} /> */}
<Route path="/Theme" element={<ThemeDemonstrator />} />
<Route path="/setup" element={<ServerSetup />} />
- <Route path="/" index element={<Home />} />
+ <Route path="/" element={<Home />} />
<Route path="*" element={<NotFoundPage />} />
</Routes>
{!state.auth.authenticated && <SignInPage key="signin" open={!state.auth.authenticated} />}
diff --git a/client/src/AuthManager.js b/client/src/AuthManager.ts
similarity index 64%
rename from client/src/AuthManager.js
rename to client/src/AuthManager.ts
index ea55c3a..77d1945 100644
--- a/client/src/AuthManager.js
+++ b/client/src/AuthManager.ts
@@ -1,6 +1,8 @@
/* eslint-disable no-undef */
// TODO: This hides eslint errors for this file. This should be removed once this file is cleaned up.
+import { PromiseExecutor } from '../../model/util';
+
/*
* Copyright (c) 2017-2021 Savoir-faire Linux Inc.
*
@@ -20,12 +22,38 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
+interface AuthManagerState {
+ initialized: boolean;
+ authenticated: boolean;
+ setupComplete: boolean;
+ error: boolean;
+}
+
+interface AuthManagerTask extends PromiseExecutor<Response> {
+ url: string;
+ init?: RequestInit;
+}
+
+interface InitData {
+ loggedin?: true;
+ username?: string;
+ type?: string;
+ setupComplete?: boolean;
+}
+
+type OnAuthChanged = (auth: AuthManagerState) => void;
+
class AuthManager {
+ private authenticating: boolean;
+ private readonly _state: AuthManagerState;
+ private tasks: AuthManagerTask[];
+ private onAuthChanged: OnAuthChanged | undefined;
+
constructor() {
console.log('AuthManager()');
this.authenticating = false;
- this.state = {
+ this._state = {
initialized: false,
authenticated: true,
setupComplete: true,
@@ -35,46 +63,48 @@
this.tasks = [];
this.onAuthChanged = undefined;
+ // @ts-ignore
if (initData) {
console.log('Using static initData');
+ // @ts-ignore
this.setInitData(initData);
return;
}
}
isAuthenticated() {
- return this.state.authenticated;
+ return this._state.authenticated;
}
getState() {
- return this.state;
+ return this._state;
}
- setInitData(data) {
+ setInitData(data: InitData) {
this.authenticating = false;
- this.state.initialized = true;
+ this._state.initialized = true;
if (data.username) {
- Object.assign(this.state, {
+ Object.assign(this._state, {
authenticated: true,
setupComplete: true,
error: false,
user: { username: data.username, type: data.type },
});
} else {
- Object.assign(this.state, {
+ Object.assign(this._state, {
authenticated: false,
- setupComplete: 'setupComplete' in data ? data.setupComplete : true,
+ setupComplete: data.setupComplete ?? true,
error: false,
});
}
console.log('Init ended');
/*if (this.onAuthChanged)
- this.onAuthChanged(this.state)*/
+ this.onAuthChanged(this._state)*/
}
- init(cb) {
+ init(cb: OnAuthChanged) {
this.onAuthChanged = cb;
- if (this.state.initialized || this.authenticating) return;
+ if (this._state.initialized || this.authenticating) return;
/*if (initData) {
console.log("Using static initData")
this.setInitData(initData)
@@ -84,14 +114,14 @@
fetch('/auth')
.then(async (response) => {
this.authenticating = false;
- this.state.initialized = true;
+ this._state.initialized = true;
if (response.status === 200) {
this.setInitData(await response.json());
} else if (response.status === 401) {
this.setInitData(await response.json());
} else {
- this.state.error = true;
- if (this.onAuthChanged) this.onAuthChanged(this.state);
+ this._state.error = true;
+ if (this.onAuthChanged) this.onAuthChanged(this._state);
}
})
.catch((e) => {
@@ -105,8 +135,8 @@
this.onAuthChanged = undefined;
}
- async setup(password) {
- if (this.authenticating || this.state.setupComplete) return;
+ async setup(password: string) {
+ if (this.authenticating || this._state.setupComplete) return;
console.log('Starting setup');
this.authenticating = true;
const response = await fetch(`/setup`, {
@@ -124,12 +154,12 @@
}
this.authenticating = false;
- this.state.setupComplete = true;
- if (this.onAuthChanged) this.onAuthChanged(this.state);
+ this._state.setupComplete = true;
+ if (this.onAuthChanged) this.onAuthChanged(this._state);
return response.ok;
}
- authenticate(username, password) {
+ authenticate(username: string, password: string) {
if (this.authenticating) return;
console.log('Starting authentication');
this.authenticating = true;
@@ -139,15 +169,20 @@
.then((response) => {
console.log(response);
this.authenticating = false;
- this.state.authenticated = response.ok && response.status === 200;
- if (this.onAuthChanged) this.onAuthChanged(this.state);
- while (this.tasks.length !== 0) {
+ this._state.authenticated = response.ok && response.status === 200;
+ if (this.onAuthChanged) this.onAuthChanged(this._state);
+ while (true) {
const task = this.tasks.shift();
- if (this.state.authenticated)
+ if (!task) {
+ break;
+ }
+ if (this._state.authenticated) {
fetch(task.url, task.init)
.then((res) => task.resolve(res))
.catch((e) => console.log('Error executing pending task: ' + e));
- else task.reject(new Error('Authentication failed'));
+ } else {
+ task.reject(new Error('Authentication failed'));
+ }
}
})
.catch((e) => {
@@ -158,17 +193,17 @@
disconnect() {
console.log('Disconnect');
- this.state.authenticated = false;
- if (this.onAuthChanged) this.onAuthChanged(this.state);
+ this._state.authenticated = false;
+ if (this.onAuthChanged) this.onAuthChanged(this._state);
}
- fetch(url, init) {
+ fetch(url: string, init?: RequestInit): Promise<Response> {
console.log(`fetch ${url}`);
- if (!this.state.authenticated) {
+ if (!this._state.authenticated) {
if (!init || !init.method || init.method === 'GET') {
- return new Promise((resolve, reject) => this.tasks.push({ url, init, resolve, reject }));
+ return new Promise<Response>((resolve, reject) => this.tasks.push({ url, init, resolve, reject }));
} else {
- return new Promise((resolve, reject) => reject('Not authenticated'));
+ return new Promise<Response>((resolve, reject) => reject('Not authenticated'));
}
}
return fetch(url, init).then((response) => {
diff --git a/client/src/i18n.js b/client/src/i18n.ts
similarity index 100%
rename from client/src/i18n.js
rename to client/src/i18n.ts
diff --git a/client/src/index.js b/client/src/index.tsx
similarity index 85%
rename from client/src/index.js
rename to client/src/index.tsx
index 2d4d46b..9a68d34 100644
--- a/client/src/index.js
+++ b/client/src/index.tsx
@@ -1,3 +1,4 @@
+/// <reference types="webpack/module" />
'use strict';
import './index.scss';
import './i18n';
@@ -5,13 +6,14 @@
// import config from "../sentry-client.config.json"
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { StrictMode } from 'react';
+import { render } from 'react-dom';
import { createRoot } from 'react-dom/client';
import { Provider } from 'react-redux';
import { BrowserRouter as Router } from 'react-router-dom';
import socketio from 'socket.io-client';
import { store } from '../redux/store';
-import App from './App.js';
+import App from './App';
import { SocketProvider } from './contexts/socket.js';
const queryClient = new QueryClient({
@@ -25,6 +27,9 @@
const socket = socketio();
const container = document.getElementById('root');
+if (!container) {
+ throw new Error('Failed to get the root element');
+}
const root = createRoot(container);
root.render(
<Provider store={store}>
@@ -43,9 +48,7 @@
if (import.meta.webpackHot)
import.meta.webpackHot.accept('./App', () => {
try {
- // TODO: This needs be fixed
- // eslint-disable-next-line no-undef
- render(App);
+ render(<App />, container);
} catch (e) {
location.reload();
}
diff --git a/client/webpack.config.js b/client/webpack.config.js
index 583b3aa..23781a2 100644
--- a/client/webpack.config.js
+++ b/client/webpack.config.js
@@ -13,7 +13,7 @@
const mode = process.env.NODE_ENV || 'development';
-let entry = [resolve(__dirname, 'src', 'index.js')];
+let entry = [resolve(__dirname, 'src', 'index.tsx')];
let plugins = [
new HtmlWebpackPlugin({
template: '!!raw-loader!' + resolve(__dirname, 'src', 'index.ejs'),