Migrate client features to use new server
Remove all authManager references where possible.
Change fetch calls url to new server.
GitLab: #79
GitLab: #100
GitLab: #110
Change-Id: I1dce64108ceba67531372df764f8f7563cc50a3b
diff --git a/client/src/pages/AccountSelection.tsx b/client/src/pages/AccountSelection.tsx
deleted file mode 100644
index f8daf0a..0000000
--- a/client/src/pages/AccountSelection.tsx
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * 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 { AddRounded } from '@mui/icons-material';
-import { Avatar, Card, CardHeader, Container, List } from '@mui/material';
-import { motion } from 'framer-motion';
-import { Account } from 'jami-web-common';
-import { Fragment, useEffect, useState } from 'react';
-import { useNavigate } from 'react-router';
-
-import authManager from '../AuthManager';
-import ConversationAvatar from '../components/ConversationAvatar';
-import Header from '../components/Header';
-import ListItemLink from '../components/ListItemLink';
-import LoadingPage from '../components/Loading';
-
-const variants = {
- enter: { opacity: 1, y: 0 },
- exit: { opacity: 0, y: '-50px' },
-};
-
-const AccountSelection = () => {
- const navigate = useNavigate();
- const [loaded, setLoaded] = useState(false);
- const [, setError] = useState(false);
- const [accounts, setAccounts] = useState<Account[]>([]);
-
- authManager.authenticate('admin', 'admin');
-
- useEffect(() => {
- const controller = new AbortController();
- authManager
- .fetch(`/api/accounts`, { signal: controller.signal })
- .then((res) => res.json())
- .then(
- (result: Account[]) => {
- console.log(result);
- if (result.length === 0) {
- navigate('/newAccount');
- } else {
- setLoaded(true);
- setAccounts(result.map((account) => Account.from(account)));
- }
- },
- (error) => {
- console.log(`get error ${error}`);
- setLoaded(true);
- setError(true);
- }
- )
- .catch((e) => console.log(e));
- // return () => controller.abort() // crash on React18
- }, [navigate]);
-
- if (!loaded) return <LoadingPage />;
- return (
- <Fragment>
- <Header />
- <Container maxWidth="sm" style={{ paddingBottom: 32 }}>
- <motion.div drag="x" initial="exit" animate="enter" exit="exit" variants={variants}>
- <Card style={{ marginTop: 32, marginBottom: 32 }}>
- <CardHeader title="Choose an account" />
- <List>
- {accounts.map((account) => (
- <ListItemLink
- key={account.getId()}
- icon={<ConversationAvatar displayName={account.getDisplayNameNoFallback()} />}
- to={`/deprecated-account/${account.getId()}/settings`}
- primary={account.getDisplayName()}
- secondary={account.getDisplayUri()}
- />
- ))}
- <ListItemLink
- icon={
- <Avatar>
- <AddRounded />
- </Avatar>
- }
- to="/newAccount"
- primary="Create new account"
- />
- </List>
- </Card>
- </motion.div>
- </Container>
- </Fragment>
- );
-};
-
-export default AccountSelection;
diff --git a/client/src/pages/AddContactPage.tsx b/client/src/pages/AddContactPage.tsx
index b0dfad0..dd93376 100644
--- a/client/src/pages/AddContactPage.tsx
+++ b/client/src/pages/AddContactPage.tsx
@@ -17,43 +17,40 @@
*/
import GroupAddRounded from '@mui/icons-material/GroupAddRounded';
import { Box, Card, CardContent, Container, Fab, Typography } from '@mui/material';
-import { useNavigate, useParams } from 'react-router-dom';
+import { useNavigate } from 'react-router-dom';
-import authManager from '../AuthManager';
+import { useAuthContext } from '../contexts/AuthProvider';
import { setRefreshFromSlice } from '../redux/appSlice';
import { useAppDispatch } from '../redux/hooks';
+import { apiUrl } from '../utils/constants';
type AddContactPageProps = {
- accountId: string;
contactId: string;
};
-export default function AddContactPage(props: AddContactPageProps) {
+export default function AddContactPage({ contactId }: AddContactPageProps) {
+ const { token } = useAuthContext();
const navigate = useNavigate();
- const params = useParams();
- const accountId = props.accountId || params.accountId;
- const contactId = props.contactId || params.contactId;
const dispatch = useAppDispatch();
const handleClick = async () => {
- const response = await authManager
- .fetch(`/api/accounts/${accountId}/conversations`, {
- method: 'POST',
- headers: {
- Accept: 'application/json',
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify({ members: [contactId] }),
- })
- .then((res) => {
- dispatch(setRefreshFromSlice());
- return res.json();
- });
+ const response = await fetch(new URL(`/conversations`, apiUrl), {
+ method: 'POST',
+ headers: {
+ Accept: 'application/json',
+ Authorization: `Bearer ${token}`,
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({ members: [contactId] }),
+ }).then((res) => {
+ dispatch(setRefreshFromSlice());
+ return res.json();
+ });
console.log(response);
if (response.conversationId) {
- navigate(`/deprecated-account/${accountId}/conversation/${response.conversationId}`);
+ navigate(`/account/conversation/${response.conversationId}`);
}
};
diff --git a/client/src/pages/ChatInterface.tsx b/client/src/pages/ChatInterface.tsx
index 4ad1830..b09f2fd 100644
--- a/client/src/pages/ChatInterface.tsx
+++ b/client/src/pages/ChatInterface.tsx
@@ -16,7 +16,7 @@
* <https://www.gnu.org/licenses/>.
*/
import { Box, Divider, Stack } from '@mui/material';
-import { Account, ConversationMember, Message } from 'jami-web-common';
+import { ConversationMember, Message } from 'jami-web-common';
import { useCallback, useContext, useEffect, useState } from 'react';
import { useDropzone } from 'react-dropzone';
@@ -29,18 +29,17 @@
import { FileHandler } from '../utils/files';
type ChatInterfaceProps = {
- account: Account;
conversationId: string;
members: ConversationMember[];
};
-const ChatInterface = ({ account, conversationId, members }: ChatInterfaceProps) => {
+const ChatInterface = ({ conversationId, members }: ChatInterfaceProps) => {
const socket = useContext(SocketContext);
const [messages, setMessages] = useState<Message[]>([]);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState(false);
- const messagesQuery = useMessagesQuery(account.getId(), conversationId);
- const sendMessageMutation = useSendMessageMutation(account.getId(), conversationId);
+ const messagesQuery = useMessagesQuery(conversationId);
+ const sendMessageMutation = useSendMessageMutation(conversationId);
const [fileHandlers, setFileHandlers] = useState<FileHandler[]>([]);
@@ -119,14 +118,14 @@
/>
)}
<input {...getInputProps()} />
- <MessageList account={account} members={members} messages={messages} />
+ <MessageList members={members} messages={messages} />
<Divider
sx={{
margin: '30px 16px 0px 16px',
borderTop: '1px solid #E5E5E5',
}}
/>
- <SendMessageForm account={account} members={members} onSend={sendMessage} openFilePicker={openFilePicker} />
+ <SendMessageForm members={members} onSend={sendMessage} openFilePicker={openFilePicker} />
{fileHandlers.length > 0 && <FilePreviewsList fileHandlers={fileHandlers} removeFile={removeFile} />}
</Stack>
);
diff --git a/client/src/pages/DeprecatedAccountSettings.tsx b/client/src/pages/DeprecatedAccountSettings.tsx
deleted file mode 100644
index f69334d..0000000
--- a/client/src/pages/DeprecatedAccountSettings.tsx
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * 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 { CircularProgress, Container } from '@mui/material';
-import { Account } from 'jami-web-common';
-import { useEffect, useState } from 'react';
-import { useParams } from 'react-router';
-
-import authManager from '../AuthManager';
-import AccountPreferences from '../components/AccountPreferences';
-import Header from '../components/Header';
-import { setAccountId } from '../redux/appSlice';
-import { useAppDispatch } from '../redux/hooks';
-
-type AccountSettingsProps = {
- accountId?: string;
- account?: Account;
-};
-
-const DeprecatedAccountSettings = (props: AccountSettingsProps) => {
- console.log('ACCOUNT SETTINGS', props.account);
- const params = useParams();
- const accountId = props.accountId || params.accountId;
-
- if (accountId == null) {
- throw new Error('Missing accountId');
- }
-
- const dispatch = useAppDispatch();
-
- const [localAccount, setLocalAccount] = useState<Account | null>(null);
-
- useEffect(() => {
- dispatch(setAccountId(accountId));
-
- const controller = new AbortController();
- authManager
- .fetch(`/api/accounts/${accountId}`, { signal: controller.signal })
- .then((res) => res.json())
- .then((result) => {
- console.log(result);
- const account = Account.from(result);
- account.setDevices(result.devices);
- setLocalAccount(account);
- })
- .catch((e) => console.log(e));
- // return () => controller.abort() // crash on React18
- }, [accountId, dispatch]);
-
- return (
- <Container maxWidth="sm">
- <Header />
- {localAccount != null ? <AccountPreferences account={localAccount} /> : <CircularProgress />}
- </Container>
- );
-};
-
-export default DeprecatedAccountSettings;
diff --git a/client/src/pages/JamiMessenger.tsx b/client/src/pages/JamiMessenger.tsx
index 2cb485b..b0b0812 100644
--- a/client/src/pages/JamiMessenger.tsx
+++ b/client/src/pages/JamiMessenger.tsx
@@ -21,6 +21,7 @@
import CallInterface from './CallInterface';
import Messenger from './Messenger';
+export type MessengerRouteParams = RouteParams<{ conversationId?: string; contactId?: string }, Record<string, never>>;
export type CallRouteParams = RouteParams<{ conversationId: string }, { video?: 'true' }>;
export default function JamiMessenger() {
diff --git a/client/src/pages/Messenger.tsx b/client/src/pages/Messenger.tsx
index c38294a..fdbb0f4 100644
--- a/client/src/pages/Messenger.tsx
+++ b/client/src/pages/Messenger.tsx
@@ -18,58 +18,60 @@
import { Stack } from '@mui/material';
import { Contact, Conversation } from 'jami-web-common';
import { useEffect, useState } from 'react';
-import { useParams } from 'react-router';
-import authManager from '../AuthManager';
//import Sound from 'react-sound';
import ConversationList from '../components/ConversationList';
import ConversationView from '../components/ConversationView';
import Header from '../components/Header';
import LoadingPage from '../components/Loading';
import NewContactForm from '../components/NewContactForm';
+import { useAuthContext } from '../contexts/AuthProvider';
import { useAppSelector } from '../redux/hooks';
+import { apiUrl } from '../utils/constants';
+import { useUrlParams } from '../utils/hooks';
import AddContactPage from './AddContactPage';
+import { MessengerRouteParams } from './JamiMessenger';
-type MessengerProps = {
- accountId?: string;
- conversationId?: string;
- contactId?: string;
-};
-
-const Messenger = (props: MessengerProps) => {
+const Messenger = () => {
const { refresh } = useAppSelector((state) => state.userInfo);
+ const { token, account } = useAuthContext();
const [conversations, setConversations] = useState<Conversation[] | undefined>(undefined);
const [searchQuery, setSearchQuery] = useState('');
const [searchResult, setSearchResults] = useState<Conversation | undefined>(undefined);
- const params = useParams();
- const accountId = props.accountId || params.accountId;
- const conversationId = props.conversationId || params.conversationId;
- const contactId = props.contactId || params.contactId;
+ const {
+ urlParams: { conversationId, contactId },
+ } = useUrlParams<MessengerRouteParams>();
- if (accountId == null) {
- throw new Error('Missing accountId');
- }
+ const accountId = account.getId();
useEffect(() => {
console.log('REFRESH CONVERSATIONS FROM MESSENGER');
const controller = new AbortController();
- authManager
- .fetch(`/api/accounts/${accountId}/conversations`, { signal: controller.signal })
+ fetch(new URL(`/conversations`, apiUrl), {
+ headers: {
+ Authorization: `Bearer ${token}`,
+ },
+ signal: controller.signal,
+ })
.then((res) => res.json())
.then((result: Conversation[]) => {
console.log(result);
setConversations(Object.values(result).map((c) => Conversation.from(accountId, c)));
});
// return () => controller.abort()
- }, [accountId, refresh]);
+ }, [token, accountId, refresh]);
useEffect(() => {
if (!searchQuery) return;
const controller = new AbortController();
- authManager
- .fetch(`/api/accounts/${accountId}/ns/name/${searchQuery}`, { signal: controller.signal })
+ fetch(new URL(`/ns/username/${searchQuery}`, apiUrl), {
+ headers: {
+ Authorization: `Bearer ${token}`,
+ },
+ signal: controller.signal,
+ })
.then((response) => {
if (response.status === 200) {
return response.json();
@@ -80,14 +82,14 @@
.then((response) => {
console.log(response);
const contact = new Contact(response.address);
- contact.setRegisteredName(response.name);
+ contact.setRegisteredName(response.username);
setSearchResults(contact ? Conversation.fromSingleContact(accountId, contact) : undefined);
})
.catch(() => {
setSearchResults(undefined);
});
// return () => controller.abort() // crash on React18
- }, [accountId, searchQuery]);
+ }, [accountId, searchQuery, token]);
console.log('Messenger render');
return (
@@ -95,7 +97,7 @@
<Stack flexGrow={0} flexShrink={0} overflow="auto">
<Header />
<NewContactForm onChange={setSearchQuery} />
- {contactId && <AddContactPage accountId={accountId} contactId={contactId} />}
+ {contactId && <AddContactPage contactId={contactId} />}
{conversations ? (
<ConversationList search={searchResult} conversations={conversations} accountId={accountId} />
) : (
@@ -104,9 +106,7 @@
</div>
)}
</Stack>
- <Stack flexGrow={1}>
- {conversationId && <ConversationView accountId={accountId} conversationId={conversationId} />}
- </Stack>
+ <Stack flexGrow={1}>{conversationId && <ConversationView conversationId={conversationId} />}</Stack>
</Stack>
);
};
diff --git a/client/src/pages/ServerConfiguration.tsx b/client/src/pages/ServerConfiguration.tsx
deleted file mode 100644
index 56d06a8..0000000
--- a/client/src/pages/ServerConfiguration.tsx
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * 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 CircularProgress from '@mui/material/CircularProgress';
-import Container from '@mui/material/Container';
-import { Account } from 'jami-web-common';
-import { useEffect, useState } from 'react';
-import { useParams } from 'react-router-dom';
-
-import authManager from '../AuthManager';
-import AccountPreferences from '../components/AccountPreferences';
-import Header from '../components/Header';
-
-type ServerOverviewProps = {
- accountId?: string;
-};
-
-const ServerOverview = (props: ServerOverviewProps) => {
- const [account, setAccount] = useState<Account | null>(null);
- const params = useParams();
- const accountId = props.accountId || params.accountId;
-
- useEffect(() => {
- const controller = new AbortController();
- authManager
- .fetch(`/api/serverConfig`, { signal: controller.signal })
- .then((res) => res.json())
- .then((result) => {
- console.log(result);
- setAccount(Account.from(result));
- })
- .catch((e) => console.log(e));
- // return () => controller.abort() // crash on React18
- }, [accountId]);
-
- return (
- <Container maxWidth="sm" className="app">
- <Header />
- {account != null ? <AccountPreferences account={account} /> : <CircularProgress />}
- </Container>
- );
-};
-
-export default ServerOverview;
diff --git a/client/src/pages/ServerSetup.tsx b/client/src/pages/ServerSetup.tsx
index e045751..e6ff0aa 100644
--- a/client/src/pages/ServerSetup.tsx
+++ b/client/src/pages/ServerSetup.tsx
@@ -19,8 +19,6 @@
import { Box, Card, CardContent, Container, Fab, Input, Typography } from '@mui/material';
import { FormEvent, useState } from 'react';
-import authManager from '../AuthManager';
-
export default function ServerSetup() {
const [password, setPassword] = useState('');
const [passwordRepeat, setPasswordRepeat] = useState('');
@@ -32,7 +30,8 @@
e.preventDefault();
setLoading(true);
if (!isValid()) return;
- authManager.setup(password);
+ // TODO: Migrate to new server
+ // authManager.setup(password);
};
return (