Decouple client from server
Add Vite dependency and remove server side rendering to make it
possible to run the client independently.
Remove webpack config, replace with the `Vite` build tool.
GitLab: #55
Change-Id: I3a05d2e86cf6cb0ab91e77b3696f393132137575
diff --git a/client/src/AuthManager.ts b/client/src/AuthManager.ts
index 29c5ffc..91ac981 100644
--- a/client/src/AuthManager.ts
+++ b/client/src/AuthManager.ts
@@ -61,14 +61,6 @@
this.tasks = [];
this.onAuthChanged = undefined;
-
- // @ts-ignore
- if (initData) {
- console.log('Using static initData');
- // @ts-ignore
- this.setInitData(initData);
- return;
- }
}
isAuthenticated() {
diff --git a/client/src/components/ContactList.js b/client/src/components/ContactList.jsx
similarity index 98%
rename from client/src/components/ContactList.js
rename to client/src/components/ContactList.jsx
index 7f8269b..2aee98b 100644
--- a/client/src/components/ContactList.js
+++ b/client/src/components/ContactList.jsx
@@ -21,8 +21,8 @@
import { useEffect, useState } from 'react';
import Modal from 'react-modal';
-import { useAppDispatch, useAppSelector } from '../../redux/hooks';
import authManager from '../AuthManager';
+import { useAppDispatch, useAppSelector } from '../redux/hooks';
import ConversationAvatar from './ConversationAvatar';
const customStyles = {
diff --git a/client/src/components/ConversationList.tsx b/client/src/components/ConversationList.tsx
index b70001a..9ad47f6 100644
--- a/client/src/components/ConversationList.tsx
+++ b/client/src/components/ConversationList.tsx
@@ -22,7 +22,7 @@
import { Conversation } from 'jami-web-common';
import { useEffect } from 'react';
-import { useAppSelector } from '../../redux/hooks';
+import { useAppSelector } from '../redux/hooks';
import ConversationListItem from './ConversationListItem';
type ConversationListProps = {
diff --git a/client/src/components/ConversationListItem.js b/client/src/components/ConversationListItem.jsx
similarity index 98%
rename from client/src/components/ConversationListItem.js
rename to client/src/components/ConversationListItem.jsx
index 0bcb0b3..16c1ccc 100644
--- a/client/src/components/ConversationListItem.js
+++ b/client/src/components/ConversationListItem.jsx
@@ -22,9 +22,9 @@
import Modal from 'react-modal';
import { useNavigate, useParams } from 'react-router-dom';
-import { setRefreshFromSlice } from '../../redux/appSlice';
-import { useAppDispatch } from '../../redux/hooks';
import authManager from '../AuthManager';
+import { setRefreshFromSlice } from '../redux/appSlice';
+import { useAppDispatch } from '../redux/hooks';
import ConversationAvatar from './ConversationAvatar';
import { RemoveContactIcon, VideoCallIcon } from './SvgIcon.tsx';
import { AudioCallIcon, BlockContactIcon, ContactDetailsIcon, CrossIcon, MessageIcon } from './SvgIcon.tsx';
diff --git a/client/src/components/ConversationsOverviewCard.js b/client/src/components/ConversationsOverviewCard.jsx
similarity index 100%
rename from client/src/components/ConversationsOverviewCard.js
rename to client/src/components/ConversationsOverviewCard.jsx
diff --git a/client/src/components/ListItemLink.js b/client/src/components/ListItemLink.jsx
similarity index 100%
rename from client/src/components/ListItemLink.js
rename to client/src/components/ListItemLink.jsx
diff --git a/client/src/components/Message.js b/client/src/components/Message.jsx
similarity index 100%
rename from client/src/components/Message.js
rename to client/src/components/Message.jsx
diff --git a/client/src/components/MessageList.js b/client/src/components/MessageList.jsx
similarity index 100%
rename from client/src/components/MessageList.js
rename to client/src/components/MessageList.jsx
diff --git a/client/src/components/UsernameChooser.js b/client/src/components/UsernameChooser.jsx
similarity index 100%
rename from client/src/components/UsernameChooser.js
rename to client/src/components/UsernameChooser.jsx
diff --git a/client/src/components/welcome.js b/client/src/components/welcome.jsx
similarity index 90%
rename from client/src/components/welcome.js
rename to client/src/components/welcome.jsx
index ca160a0..39e222b 100644
--- a/client/src/components/welcome.js
+++ b/client/src/components/welcome.jsx
@@ -19,8 +19,6 @@
import { AnimatePresence, motion } from 'framer-motion';
import { useState } from 'react';
-import JamiLogo from '../../public/jami-logo-icon.svg';
-
const list = {
hidden: { opacity: 0 },
visible: {
@@ -57,7 +55,14 @@
}}
>
<motion.div variants={item}>
- <JamiLogo size="32px" />
+ <img
+ src="/jami-logo-icon.svg"
+ style={{
+ width: '32',
+ height: '32',
+ }}
+ alt="jami n/logo"
+ />
</motion.div>
<motion.h1 variants={item}>Welcome to Jami</motion.h1>
{props.showSetup && (
diff --git a/client/src/i18n.ts b/client/src/i18n.ts
index 63d7e1c..37f9f7f 100644
--- a/client/src/i18n.ts
+++ b/client/src/i18n.ts
@@ -18,11 +18,11 @@
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
-import translationEn from '../public/locale/en/translation.json';
-import translationFr from '../public/locale/fr/translation.json';
+import translationEn from './locale/en/translation.json';
+import translationFr from './locale/fr/translation.json';
i18n.use(initReactI18next).init({
- debug: process.env.NODE_ENV == 'development',
+ debug: import.meta.env.DEV,
lng: 'en',
interpolation: {
escapeValue: false,
diff --git a/client/src/index.ejs b/client/src/index.ejs
deleted file mode 100644
index d68639a..0000000
--- a/client/src/index.ejs
+++ /dev/null
@@ -1,18 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-
-<head>
- <meta charset="utf-8" />
- <link rel="icon" href="/favicon.png" />
- <link rel="apple-touch-icon" href="/logo192.png" />
- <meta name="viewport" content="minimum-scale=1, initial-scale=1, width=device-width" />
- <meta name="description" content="Jami Web" />
- <script>const initData=<%- initdata %></script>
- <title>Jami Web</title>
-</head>
-
-<body>
- <div id="root"></div>
-</body>
-
-</html>
\ No newline at end of file
diff --git a/client/src/index.tsx b/client/src/index.tsx
index fdd2fe7..83c2ada 100644
--- a/client/src/index.tsx
+++ b/client/src/index.tsx
@@ -15,7 +15,6 @@
* License along with this program. If not, see
* <https://www.gnu.org/licenses/>.
*/
-/// <reference types="webpack/module" />
'use strict';
import './index.scss';
import './i18n';
@@ -23,15 +22,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';
import { SocketProvider } from './contexts/Socket';
+import { store } from './redux/store';
const queryClient = new QueryClient({
defaultOptions: {
@@ -61,12 +59,3 @@
</StrictMode>
</Provider>
);
-
-if (import.meta.webpackHot)
- import.meta.webpackHot.accept('./App', () => {
- try {
- render(<App />, container);
- } catch (e) {
- location.reload();
- }
- });
diff --git a/client/src/locale/en/translation.json b/client/src/locale/en/translation.json
new file mode 100644
index 0000000..19ddf26
--- /dev/null
+++ b/client/src/locale/en/translation.json
@@ -0,0 +1,4 @@
+{
+ "message_swarm_created": "Swarm created",
+ "message_user_joined": "{{user}} joined"
+}
diff --git a/client/src/locale/fr/translation.json b/client/src/locale/fr/translation.json
new file mode 100644
index 0000000..332c3d4
--- /dev/null
+++ b/client/src/locale/fr/translation.json
@@ -0,0 +1,4 @@
+{
+ "message_swarm_created": "Le Swarm a été créé",
+ "message_user_joined": "{{user}} s'est joint"
+}
diff --git a/client/src/pages/AccountSettings.tsx b/client/src/pages/AccountSettings.tsx
index 35c0678..fe98277 100644
--- a/client/src/pages/AccountSettings.tsx
+++ b/client/src/pages/AccountSettings.tsx
@@ -20,11 +20,11 @@
import { useEffect, useState } from 'react';
import { useParams } from 'react-router';
-import { setAccountId, setAccountObject } from '../../redux/appSlice';
-import { useAppDispatch } from '../../redux/hooks';
import authManager from '../AuthManager';
import AccountPreferences from '../components/AccountPreferences';
import Header from '../components/Header';
+import { setAccountId, setAccountObject } from '../redux/appSlice';
+import { useAppDispatch } from '../redux/hooks';
type AccountSettingsProps = {
accountId?: string;
diff --git a/client/src/pages/AddContactPage.tsx b/client/src/pages/AddContactPage.tsx
index d9c8394..666625c 100644
--- a/client/src/pages/AddContactPage.tsx
+++ b/client/src/pages/AddContactPage.tsx
@@ -19,9 +19,9 @@
import { Box, Card, CardContent, Container, Fab, Typography } from '@mui/material';
import { useNavigate, useParams } from 'react-router-dom';
-import { setRefreshFromSlice } from '../../redux/appSlice';
-import { useAppDispatch } from '../../redux/hooks';
import authManager from '../AuthManager';
+import { setRefreshFromSlice } from '../redux/appSlice';
+import { useAppDispatch } from '../redux/hooks';
type AddContactPageProps = {
accountId: string;
diff --git a/client/src/pages/Messenger.tsx b/client/src/pages/Messenger.tsx
index 1fd2252..6aeb840 100644
--- a/client/src/pages/Messenger.tsx
+++ b/client/src/pages/Messenger.tsx
@@ -20,7 +20,6 @@
import { useEffect, useState } from 'react';
import { useParams } from 'react-router';
-import { useAppSelector } from '../../redux/hooks';
import authManager from '../AuthManager';
//import Sound from 'react-sound';
import ConversationList from '../components/ConversationList';
@@ -28,6 +27,7 @@
import Header from '../components/Header';
import LoadingPage from '../components/Loading';
import NewContactForm from '../components/NewContactForm';
+import { useAppSelector } from '../redux/hooks';
import AddContactPage from './AddContactPage';
type MessengerProps = {
diff --git a/client/src/redux/appSlice.ts b/client/src/redux/appSlice.ts
new file mode 100644
index 0000000..d5c01ee
--- /dev/null
+++ b/client/src/redux/appSlice.ts
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2022 Savoir-faire Linux Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this program. If not, see
+ * <https://www.gnu.org/licenses/>.
+ */
+import { createSlice, PayloadAction } from '@reduxjs/toolkit';
+import { Account } from 'jami-web-common';
+
+// Define a type for the slice state
+export interface appState {
+ accountId: string;
+ accountObject: Account | null;
+ refresh: boolean;
+}
+
+// Define the initial state using that type
+const initialState: appState = {
+ accountId: '',
+ accountObject: null,
+ refresh: true,
+};
+
+export const appSlice = createSlice({
+ name: 'app',
+ // `createSlice` will infer the state type from the `initialState` argument
+ initialState,
+ reducers: {
+ setAccountId: (state, action: PayloadAction<string>) => {
+ state.accountId = action.payload;
+ },
+ setAccountObject: (state, action: PayloadAction<Account>) => {
+ state.accountObject = action.payload;
+ },
+ setRefreshFromSlice: (state) => {
+ state.refresh = !state.refresh;
+ },
+ },
+});
+
+export const { setAccountId, setAccountObject, setRefreshFromSlice } = appSlice.actions;
+
+// Other code such as selectors can use the imported `RootState` type
+// export const selectCount = (state: RootState) => state.app.value;
+
+export default appSlice.reducer;
diff --git a/client/src/redux/hooks.ts b/client/src/redux/hooks.ts
new file mode 100644
index 0000000..146b3b1
--- /dev/null
+++ b/client/src/redux/hooks.ts
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2022 Savoir-faire Linux Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this program. If not, see
+ * <https://www.gnu.org/licenses/>.
+ */
+import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
+
+import type { AppDispatch, RootState } from './store';
+
+// Use throughout your app instead of plain `useDispatch` and `useSelector`
+export const useAppDispatch: () => AppDispatch = useDispatch;
+export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
diff --git a/client/src/redux/store.ts b/client/src/redux/store.ts
new file mode 100644
index 0000000..be2b4a5
--- /dev/null
+++ b/client/src/redux/store.ts
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2022 Savoir-faire Linux Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this program. If not, see
+ * <https://www.gnu.org/licenses/>.
+ */
+import { configureStore } from '@reduxjs/toolkit';
+
+import appReducer from './appSlice';
+
+export const store = configureStore({
+ reducer: {
+ app: appReducer,
+ },
+});
+
+// Infer the `RootState` and `AppDispatch` types from the store itself
+export type RootState = ReturnType<typeof store.getState>;
+// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
+export type AppDispatch = typeof store.dispatch;