implement list of contacts and CRUD contacts API route
Change-Id: I749d25c8b1ef6205e5d888bb517c43233bc9215b
diff --git a/JamiDaemon.js b/JamiDaemon.js
index f25f743..7f92f38 100755
--- a/JamiDaemon.js
+++ b/JamiDaemon.js
@@ -251,6 +251,11 @@
JamiDaemon.mapToJs(this.dring.getAccountDetails(accountId)),
JamiDaemon.mapToJs(this.dring.getVolatileAccountDetails(accountId))
)
+
+ account.contacts = JamiDaemon.vectMapToJs(
+ this.dring.getContacts(accountId)
+ );
+
JamiDaemon.vectToJs(this.dring.getConversations(accountId)).forEach(conversationId => {
const members = JamiDaemon.vectMapToJs(this.dring.getConversationMembers(accountId, conversationId))
members.forEach(member => {
@@ -399,6 +404,20 @@
return details
}
+ removeContact(accountId, contactId){
+ //bool ban false
+ this.dring.removeContact(accountId, contactId, false);
+ }
+
+ blockContact(accountId, contactId){
+ //bool ban true
+ this.dring.removeContact(accountId, contactId, true);
+ }
+
+ getContactDetails(accountId, contactId){
+ return JamiDaemon.mapToJs(this.dring.getContactDetails(accountId, contactId))
+ }
+
getDefaultModerators(accountId) {
const account = this.getAccount(accountId)
if (!account) {
diff --git a/client/redux/appSlice.ts b/client/redux/appSlice.ts
index e430aad..8ad47cd 100644
--- a/client/redux/appSlice.ts
+++ b/client/redux/appSlice.ts
@@ -1,14 +1,17 @@
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
+import Account from "../../model/Account";
import type { RootState } from "./store";
// Define a type for the slice state
interface appState {
accountId: string;
+ accountObject: Account;
}
// Define the initial state using that type
const initialState: appState = {
accountId: "",
+ accountObject: null,
};
export const appSlice = createSlice({
@@ -19,10 +22,13 @@
setAccountId: (state, action: PayloadAction<string>) => {
state.accountId = action.payload;
},
+ setAccountObject: (state, action: PayloadAction<Account>) => {
+ state.accountObject = action.payload ;
+ },
},
});
-export const { setAccountId } = appSlice.actions;
+export const { setAccountId, setAccountObject } = appSlice.actions;
// Other code such as selectors can use the imported `RootState` type
// export const selectCount = (state: RootState) => state.app.value;
diff --git a/client/src/components/ContactList.js b/client/src/components/ContactList.js
index 73950a2..b15238f 100644
--- a/client/src/components/ContactList.js
+++ b/client/src/components/ContactList.js
@@ -1,35 +1,163 @@
import List from "@mui/material/List";
import authManager from "../AuthManager";
+import ConversationAvatar from "./ConversationAvatar";
+import Modal from 'react-modal';
import React, { useState, useEffect } from "react";
+import { Person } from "@mui/icons-material";
import { useAppDispatch, useAppSelector } from "../../redux/hooks";
+import { ListItem, ListItemAvatar, ListItemText } from "@mui/material";
+const customStyles = {
+ content: {
+ top: "50%",
+ left: "50%",
+ right: "auto",
+ bottom: "auto",
+ marginRight: "-50%",
+ transform: "translate(-50%, -50%)",
+ },
+};
export default function ContactList() {
- const { accountId } = useAppSelector((state) => state.app);
+ const { accountId, accountObject } = useAppSelector((state) => state.app);
const dispatch = useAppDispatch();
const [contacts, setContacts] = useState([]);
+ const [currentContact, setCurrentContact] = useState({});
+
+ const [modalIsOpen, setIsOpen] = useState(false);
+ const [modalDetailsIsOpen, setModalDetailsIsOpen] = useState(false);
+ const [modalDeleteIsOpen, setModalDeleteIsOpen] = useState(false);
+
+ const openModal = () => setIsOpen(true);
+ const openModalDetails = () => setModalDetailsIsOpen(true);
+ const openModalDelete = () => setModalDeleteIsOpen(true);
+
+ const closeModal = () => setIsOpen(false);
+
+ const closeModalDetails = () => setModalDetailsIsOpen(false);
+ const closeModalDelete = () => setModalDeleteIsOpen(false);
+
+ const getContactDetails = () => {
+ const controller = new AbortController();
+ authManager
+ .fetch(`/api/accounts/${accountId}/contacts/${currentContact.id}`, {
+ signal: controller.signal,
+ })
+ .then((res) => res.json())
+ .then((result) => {
+ // setContacts(result);
+ console.log("CONTACT LIST - DETAILS: ", result);
+ })
+ .catch((e) => console.log("ERROR 2", e));
+ };
+
+ const removeContact = () => {};
+
+ const blockContact = () => {};
+
useEffect(() => {
const controller = new AbortController();
authManager
- .fetch(`/api/accounts/${accountId}/contacts/`, {
- method: "GET",
- header: { "Content-Type": "application/json" },
- // signal: controller.signal,
+ .fetch(`/api/accounts/${accountId}/conversations`, {
+ signal: controller.signal,
})
- .then((res) => {
- res.json();
- })
+ .then((res) => res.json())
.then((result) => {
- console.log(result);
+ setContacts(result);
});
return () => controller.abort();
}, []);
return (
<div className="rooms-list">
- <List></List>
+ <Modal
+ isOpen={modalIsOpen}
+ // onAfterOpen={afterOpenModal}
+ onRequestClose={closeModal}
+ style={customStyles}
+ contentLabel="Example Modal"
+ >
+ {/* <h2 ref={(_subtitle) => (subtitle = _subtitle)}>Hello</h2> */}
+ <button onClick={closeModal}>close</button>
+
+ {/* <div>
+ <Person /> Démarrer appel vidéo
+ </div>
+ <br />
+
+ <div>
+ <Person /> Démarrer appel audio
+ </div> */}
+ <br />
+
+ <div
+ onClick={() => {
+ console.log("open dialog Supprimer: ");
+ closeModal();
+ openModalDelete();
+ }}
+ >
+ <Person /> Supprimer contact
+ </div>
+ <br />
+
+ <div
+ onClick={() => {
+ console.log("open dialog BLOCK: ");
+ closeModal();
+ openModalDelete();
+ }}
+ >
+ <Person /> Bloquer le contact
+ </div>
+ <br />
+
+ <div
+ onClick={() => {
+ console.log("open details contact for: ");
+ closeModal();
+ openModalDetails();
+ getContactDetails();
+ }}
+ >
+ <Person /> Détails du contact
+ </div>
+ </Modal>
+ <Modal
+ isOpen={modalDeleteIsOpen}
+ // onAfterOpen={afterOpenModalDetails}
+ onRequestClose={closeModalDelete}
+ style={customStyles}
+ contentLabel="Merci de confirmer"
+ >
+ Voulez vous vraiment supprimer ce contact?
+ <button onClick={closeModalDelete}>Bloquer</button>
+ <button onClick={closeModalDelete}>Annuler</button>
+ </Modal>
+
+ <List>
+ {contacts.map((contact) => (
+ <ListItem
+ button
+ alignItems="flex-start"
+ // selected={isSelected}
+ onClick={() => {
+ setCurrentContact(contact);
+ openModal();
+ }}
+ >
+ <ListItemAvatar>
+ <ConversationAvatar
+ // displayName={conversation.getDisplayNameNoFallback()}
+ // displayName={`${contact.id}`}
+ />
+ </ListItemAvatar>
+ <ListItemText primary={contact.id} secondary={contact.id} />
+ </ListItem>
+ ))}
+ </List>
</div>
);
}
diff --git a/client/src/components/ConversationListItem.js b/client/src/components/ConversationListItem.js
index 26736e9..b45f562 100644
--- a/client/src/components/ConversationListItem.js
+++ b/client/src/components/ConversationListItem.js
@@ -75,7 +75,6 @@
})
.then((result) => {
console.log("YYY 1", result);
- // setState({ loaded: true, account: Account.from(result) });
})
.catch((e) => console.log("YYY 2", e));
// return () => controller.abort()
diff --git a/client/src/components/ListItemLink.js b/client/src/components/ListItemLink.js
index 915a24b..a0ebc3b 100644
--- a/client/src/components/ListItemLink.js
+++ b/client/src/components/ListItemLink.js
@@ -6,10 +6,12 @@
import { Link as RouterLink } from 'react-router-dom';
function ListItemLink(props) {
- const { icon, primary, secondary, to } = props
+ const { icon, primary, secondary, to, account } = props
const renderLink = useMemo(
- () => forwardRef((itemProps, ref) => <RouterLink to={to} ref={ref} {...itemProps} />),
+ () => forwardRef((itemProps, ref) => {
+ console.log("LIST ITEM LINK: ", account, itemProps)
+ return <RouterLink to={to} ref={ref} {...itemProps} state={account}/>}),
[to])
return (
@@ -25,6 +27,7 @@
primary: PropTypes.string.isRequired,
secondary: PropTypes.string,
to: PropTypes.string.isRequired,
+ account: PropTypes.object
}
export default ListItemLink
\ No newline at end of file
diff --git a/client/src/pages/accountSettings.jsx b/client/src/pages/accountSettings.jsx
index d555820..fa29a7d 100644
--- a/client/src/pages/accountSettings.jsx
+++ b/client/src/pages/accountSettings.jsx
@@ -6,9 +6,10 @@
import authManager from '../AuthManager'
import Account from '../../../model/Account'
import { useAppSelector, useAppDispatch } from '../../redux/hooks';
-import { setAccountId } from '../../redux/appSlice';
+import { setAccountId, setAccountObject } from '../../redux/appSlice';
const AccountSettings = (props) => {
+ console.log("ACCOUNT SETTINGS", props.account)
const accountId = props.accountId || useParams().accountId
const dispatch = useAppDispatch();
@@ -23,6 +24,7 @@
.then(result => {
let account = Account.from(result)
account.setDevices(result.devices)
+ dispatch(setAccountObject(account))
setState({ loaded: true, account: account})
}).catch(e => console.log(e))
diff --git a/routes/jami.js b/routes/jami.js
index 7ed056e..cbe3286 100644
--- a/routes/jami.js
+++ b/routes/jami.js
@@ -6,8 +6,8 @@
}
getRouter() {
- const router = Router({mergeParams: true})
- //router.use(express.json());
+ const router = Router({ mergeParams: true });
+ //router.use(express.json());
// Accounts
router.get('/accounts', async (req, res) => {
@@ -53,7 +53,7 @@
router.use('/accounts/:accountId', checkAccount, accountRouter)
accountRouter.get('/', async (req, res) => {
- console.log(`BBBBBBB Get account ${req.params.accountId}`)
+ console.log(`Get account ${req.params.accountId}`)
const account = this.jami.getAccount(req.params.accountId)
if (account) {
account.defaultModerators = this.jami.getDefaultModerators(account.getId())
@@ -68,7 +68,6 @@
console.log(`Set account details ${req.params.accountId}`);
const account = this.jami.getAccount(req.params.accountId);
if (account) {
- console.log(req.body);
const newDetails = account.updateDetails(req.body);
this.jami.setAccountDetails(account.getId(), newDetails);
res.status(200).end();
@@ -77,17 +76,15 @@
// Contacts
accountRouter.get("/contacts", (req, res) => {
- console.log(`AAAAAAAA Get account ${req.params.accountId}`);
+ console.log(`Get account ${req.params.accountId}`);
const account = this.jami.getAccount(req.params.accountId);
if (account) {
let rep = account.getContacts();
- console.log(rep);
res.json(rep);
} else res.status(404).end();
});
accountRouter.get("/contacts/:contactId", (req, res) => {
- console.log("CCCCCCC JAMI.JS: ", req.params);
console.log(`Get account details fot ${req.params.accountId}`);
const account = this.jami.getAccount(req.params.accountId);
const uri = req.params.uri;
@@ -97,140 +94,179 @@
} else res.status(404).end();
});
- // Default modertors
- accountRouter.put("/defaultModerators/:contactId", async (req, res) => {
+
+
+
+
+ // Default modertors
+ accountRouter.put("/defaultModerators/:contactId", async (req, res) => {
+ console.log(
+ `Adding default moderator ${req.params.contactId} to account ${req.params.accountId}`
+ );
+ this.jami.addDefaultModerator(
+ req.params.accountId,
+ req.params.contactId
+ );
+ res.status(200).end();
+ });
+
+ accountRouter.delete(
+ "/defaultModerators/:contactId",
+ async (req, res) => {
console.log(
- `Adding default moderator ${req.params.contactId} to account ${req.params.accountId}`
+ `Removing default moderator to account ${req.params.accountId}`
);
- this.jami.addDefaultModerator(
+ this.jami.removeDefaultModerator(
req.params.accountId,
req.params.contactId
);
res.status(200).end();
- });
+ }
+ );
- accountRouter.delete('/defaultModerators/:contactId', async (req, res) => {
- console.log(`Removing default moderator to account ${req.params.accountId}`)
- this.jami.removeDefaultModerator(req.params.accountId, req.params.contactId)
- res.status(200).end()
- })
-
- // Conversations
- accountRouter.get('/conversations', async (req, res, next) => {
- console.log(`Get conversations for account ${req.params.accountId}`)
- const account = this.jami.getAccount(req.params.accountId)
- if (!account)
- return res.sendStatus(404)
- const conversations = account.getConversations()
- res.json(await Promise.all(Object.keys(conversations).map(async conversationId => await conversations[conversationId].getObject({
- memberFilter: member => member.contact.getUri() !== account.getUri()
- }))))
- //res.json(account.getConversations())
- })
-
- accountRouter.post('/conversations', (req, res) => {
- console.log(`Create conversations for account, contact ${req.params.accountId}`)
- console.log(req.body)
- const account = this.jami.getAccount(req.params.accountId)
- if (!account)
- return res.sendStatus(404)
- if (req.body.members.length === 1) {
- const details = this.jami.addContact(req.params.accountId, req.body.members[0])
- res.json(details)
- } else
- res.status(400).end()
- })
-
- accountRouter.post('/conversations/:conversationId', async (req, res) => {
- console.log(`Sending message to ${req.params.conversationId} for account ${req.params.accountId}`)
- this.jami.sendMessage(req.params.accountId, req.params.conversationId, req.body.message)
- res.status(200).end()
- })
-
- accountRouter.get('/conversations/:conversationId', async (req, res) => {
- console.log(`Get conversation ${req.params.conversationId} for account ${req.params.accountId}`)
- const account = this.jami.getAccount(req.params.accountId)
- if (!account)
- return res.sendStatus(404)
- const conversation = account.getConversation(req.params.conversationId)
- if (!conversation)
- res.status(404).end()
- else {
- res.json(await conversation.getObject({
- memberFilter: member => member.contact.getUri() !== account.getUri()
- }))
- }
- })
-
- accountRouter.get('/conversations/:conversationId/messages', async (req, res) => {
- console.log(`Get messages for conversation ${req.params.conversationId} for account ${req.params.accountId}`)
- try {
- const messages = await this.jami.loadMessages(req.params.accountId, req.params.conversationId)
- res.json(messages).end()
- } catch (e) {
- res.status(400).json({ error: e.message })
- }
- })
-
- // Calls
-
- accountRouter.get('/calls', async (req, res) => {
- console.log(`Get calls for account ${req.params.accountId}`)
- try {
- const calls = await this.jami.getCalls(req.params.accountId)
- res.json(calls).end()
- } catch (e) {
- res.status(400).json({ error: e.message })
- }
- })
-
- accountRouter.get('/calls/:callId', async (req, res) => {
- console.log(`Get call ${callId} for account ${req.params.accountId}`)
- try {
- const messages = await this.jami.getCall(req.params.accountId, req.params.callId)
- res.json(messages).end()
- } catch (e) {
- res.status(400).json({ error: e.message })
- }
- })
-
- // Nameserver
- const nsRouter = Router({mergeParams: true})
- accountRouter.use('/ns', nsRouter) // use account nameserver
- router.use('/ns', nsRouter) // use default nameserver
-
- nsRouter.get(['/name/:nameQuery'], (req, res, next) => {
- console.log(`Name lookup ${req.params.nameQuery}`)
- this.jami.lookupName(req.params.accountId || '', req.params.nameQuery)
- .then(result => {
- if (result.state == 0)
- res.json(result)
- else if (result.state == 1)
- res.status(400).json({})
- else
- res.status(404).json({})
- }).catch(e => {
- res.status(404).json({})
+ // Conversations
+ accountRouter.get("/conversations", async (req, res, next) => {
+ console.log(`Get conversations for account ${req.params.accountId}`);
+ const account = this.jami.getAccount(req.params.accountId);
+ if (!account) return res.sendStatus(404);
+ const conversations = account.getConversations();
+ res.json(
+ await Promise.all(
+ Object.keys(conversations).map(
+ async (conversationId) =>
+ await conversations[conversationId].getObject({
+ memberFilter: (member) =>
+ member.contact.getUri() !== account.getUri(),
})
- })
+ )
+ )
+ );
+ //res.json(account.getConversations())
+ });
- nsRouter.get(['/addr/:addrQuery'], (req, res, next) => {
- console.log(`Address lookup ${req.params.addrQuery}`)
- this.jami.lookupAddress(req.params.accountId || '', req.params.addrQuery)
- .then(result => {
- if (result.state == 0)
- res.json(result)
- else if (result.state == 1)
- res.status(400).json({})
- else
- res.status(404).json({})
- }).catch(e => {
- res.status(404).json({})
- })
- })
+ accountRouter.post("/conversations", (req, res) => {
+ console.log(
+ `Create conversations for account, contact ${req.params.accountId}`
+ );
+ // console.log(req.body)
+ const account = this.jami.getAccount(req.params.accountId);
+ if (!account) return res.sendStatus(404);
+ if (req.body.members.length === 1) {
+ const details = this.jami.addContact(
+ req.params.accountId,
+ req.body.members[0]
+ );
+ res.json(details);
+ } else res.status(400).end();
+ });
+ accountRouter.post("/conversations/:conversationId", async (req, res) => {
+ console.log(
+ `Sending message to ${req.params.conversationId} for account ${req.params.accountId}`
+ );
+ this.jami.sendMessage(
+ req.params.accountId,
+ req.params.conversationId,
+ req.body.message
+ );
+ res.status(200).end();
+ });
- return router
+ accountRouter.get("/conversations/:conversationId", async (req, res) => {
+ console.log(
+ `Get conversation ${req.params.conversationId} for account ${req.params.accountId}`
+ );
+ const account = this.jami.getAccount(req.params.accountId);
+ if (!account) return res.sendStatus(404);
+ const conversation = account.getConversation(req.params.conversationId);
+ if (!conversation) res.status(404).end();
+ else {
+ res.json(
+ await conversation.getObject({
+ memberFilter: (member) =>
+ member.contact.getUri() !== account.getUri(),
+ })
+ );
+ }
+ });
+
+ accountRouter.get(
+ "/conversations/:conversationId/messages",
+ async (req, res) => {
+ console.log(
+ `Get messages for conversation ${req.params.conversationId} for account ${req.params.accountId}`
+ );
+ try {
+ const messages = await this.jami.loadMessages(
+ req.params.accountId,
+ req.params.conversationId
+ );
+ res.json(messages).end();
+ } catch (e) {
+ res.status(400).json({ error: e.message });
+ }
+ }
+ );
+
+ // Calls
+
+ accountRouter.get("/calls", async (req, res) => {
+ console.log(`Get calls for account ${req.params.accountId}`);
+ try {
+ const calls = await this.jami.getCalls(req.params.accountId);
+ res.json(calls).end();
+ } catch (e) {
+ res.status(400).json({ error: e.message });
+ }
+ });
+
+ accountRouter.get("/calls/:callId", async (req, res) => {
+ console.log(`Get call ${callId} for account ${req.params.accountId}`);
+ try {
+ const messages = await this.jami.getCall(
+ req.params.accountId,
+ req.params.callId
+ );
+ res.json(messages).end();
+ } catch (e) {
+ res.status(400).json({ error: e.message });
+ }
+ });
+
+ // Nameserver
+ const nsRouter = Router({ mergeParams: true });
+ accountRouter.use("/ns", nsRouter); // use account nameserver
+ router.use("/ns", nsRouter); // use default nameserver
+
+ nsRouter.get(["/name/:nameQuery"], (req, res, next) => {
+ console.log(`Name lookup ${req.params.nameQuery}`);
+ this.jami
+ .lookupName(req.params.accountId || "", req.params.nameQuery)
+ .then((result) => {
+ if (result.state == 0) res.json(result);
+ else if (result.state == 1) res.status(400).json({});
+ else res.status(404).json({});
+ })
+ .catch((e) => {
+ res.status(404).json({});
+ });
+ });
+
+ nsRouter.get(["/addr/:addrQuery"], (req, res, next) => {
+ console.log(`Address lookup ${req.params.addrQuery}`);
+ this.jami
+ .lookupAddress(req.params.accountId || "", req.params.addrQuery)
+ .then((result) => {
+ if (result.state == 0) res.json(result);
+ else if (result.state == 1) res.status(400).json({});
+ else res.status(404).json({});
+ })
+ .catch((e) => {
+ res.status(404).json({});
+ });
+ });
+
+ return router;
}
}