add account overview, cleanup

Change-Id: I176af7a7688f38cb30eb7d65fa3e00e55f10da6f
diff --git a/client/src/components/AccountList.js b/client/src/components/AccountList.js
index 38f1291..594c979 100644
--- a/client/src/components/AccountList.js
+++ b/client/src/components/AccountList.js
@@ -1,6 +1,6 @@
 import React from 'react'
-import { Avatar, List, ListItem, ListItemAvatar, ListItemText } from '@material-ui/core'
-import { PersonRounded } from '@material-ui/icons';
+import { List, ListItem, ListItemAvatar, ListItemText } from '@material-ui/core'
+import ConversationAvatar from './ConversationAvatar'
 
 export default function AccountList(props) {
   return <List>
@@ -9,7 +9,7 @@
         const displayName = account.getDisplayNameNoFallback()
         return <ListItem button key={account.getId()} onClick={() => props.onClick(account)}>
           <ListItemAvatar>
-            <Avatar>{displayName ? displayName[0].toUpperCase() : <PersonRounded />}</Avatar>
+            <ConversationAvatar displayName={displayName} />
           </ListItemAvatar>
           <ListItemText primary={account.getDisplayName()} secondary={account.getDisplayUri()} />
         </ListItem>
diff --git a/client/src/components/AccountPreferences.js b/client/src/components/AccountPreferences.js
index 5b6ae28..5629ef0 100644
--- a/client/src/components/AccountPreferences.js
+++ b/client/src/components/AccountPreferences.js
@@ -1,63 +1,142 @@
 import React from 'react';
-
-import Typography from '@material-ui/core/Typography';
+import { makeStyles } from '@material-ui/core/styles';
+import { List, ListItem, ListItemIcon, ListItemSecondaryAction, ListItemText, ListSubheader, Switch, Typography, Grid, Paper, CardContent, Card } from '@material-ui/core';
+import { PhoneCallbackRounded, GroupRounded } from '@material-ui/icons';
 
 import JamiIdCard from './JamiIdCard';
-import List from '@material-ui/core/List';
-import ListItem from '@material-ui/core/ListItem';
-import ListItemIcon from '@material-ui/core/ListItemIcon';
-import ListItemSecondaryAction from '@material-ui/core/ListItemSecondaryAction';
-import ListItemText from '@material-ui/core/ListItemText';
-import ListSubheader from '@material-ui/core/ListSubheader';
-import Switch from '@material-ui/core/Switch';
-import PhoneCallbackIcon from '@material-ui/icons/PhoneCallback';
-import GroupRoundedIcon from '@material-ui/icons/GroupRounded';
 import Account from '../../../model/Account';
+import ConversationsOverviewCard from './ConversationsOverviewCard';
 
-class AccountPreferences extends React.Component {
+const useStyles = makeStyles({
+  root: {
+    minWidth: 275,
+  },
+  bullet: {
+    display: 'inline-block',
+    margin: '0 2px',
+    transform: 'scale(0.8)',
+  },
+  title: {
+    fontSize: 14,
+  },
+  pos: {
+    marginBottom: 12,
+  },
+});
 
-  render() {
-    const account = this.props.account
-    const isJamiAccount = account.getType() === Account.TYPE_JAMI
-    return (
-      <React.Fragment>
-        <Typography variant="h2" component="h2">{isJamiAccount ? "Jami account" : "SIP account"}</Typography>
+const columns = [
+  { id: 'name', label: 'Name', minWidth: 170 },
+  { id: 'code', label: 'ISO\u00a0Code', minWidth: 100 },
+  {
+    id: 'population',
+    label: 'Population',
+    minWidth: 170,
+    align: 'right',
+    format: (value) => value.toLocaleString('en-US'),
+  },
+  {
+    id: 'size',
+    label: 'Size\u00a0(km\u00b2)',
+    minWidth: 170,
+    align: 'right',
+    format: (value) => value.toLocaleString('en-US'),
+  },
+  {
+    id: 'density',
+    label: 'Density',
+    minWidth: 170,
+    align: 'right',
+    format: (value) => value.toFixed(2),
+  },
+];
 
-        {isJamiAccount &&
-          <JamiIdCard account={account} />}
-
-        <List subheader={<ListSubheader>Settings</ListSubheader>}>
-          <ListItem>
-            <ListItemIcon>
-              <GroupRoundedIcon />
-            </ListItemIcon>
-            <ListItemText id="switch-list-label-rendezvous" primary="Rendez-Vous point" />
-            <ListItemSecondaryAction>
-              <Switch
-                edge="end"
-                /*onChange={handleToggle('wifi')}*/
-                checked={account.isRendezVous()}
-                inputProps={{ 'aria-labelledby': 'switch-list-label-wifi' }}
-              />
-            </ListItemSecondaryAction>
-          </ListItem>
-          <ListItem>
-            <ListItemIcon>
-              <PhoneCallbackIcon />
-            </ListItemIcon>
-            <ListItemText id="switch-list-label-publicin" primary="Allow connection from unkown peers" />
-            <ListItemSecondaryAction>
-              <Switch
-                edge="end"
-                /*onChange={handleToggle('bluetooth')}*/
-                checked={account.isPublicIn()}
-                inputProps={{ 'aria-labelledby': 'switch-list-label-bluetooth' }}
-              />
-            </ListItemSecondaryAction>
-          </ListItem>
-        </List>
-      </React.Fragment>)
-  }
+function createData(name, code, population, size) {
+  const density = population / size;
+  return { name, code, population, size, density };
 }
 
-export default AccountPreferences;
\ No newline at end of file
+const rows = [
+  createData('India', 'IN', 1324171354, 3287263),
+  createData('China', 'CN', 1403500365, 9596961),
+  createData('Italy', 'IT', 60483973, 301340),
+  createData('United States', 'US', 327167434, 9833520),
+  createData('Canada', 'CA', 37602103, 9984670),
+  createData('Australia', 'AU', 25475400, 7692024),
+  createData('Germany', 'DE', 83019200, 357578),
+  createData('Ireland', 'IE', 4857000, 70273),
+  createData('Mexico', 'MX', 126577691, 1972550),
+  createData('Japan', 'JP', 126317000, 377973),
+  createData('France', 'FR', 67022000, 640679),
+  createData('United Kingdom', 'GB', 67545757, 242495),
+  createData('Russia', 'RU', 146793744, 17098246),
+  createData('Nigeria', 'NG', 200962417, 923768),
+  createData('Brazil', 'BR', 210147125, 8515767),
+];
+
+export default function AccountPreferences(props) {
+  const classes = useStyles()
+  const account = props.account
+  const isJamiAccount = account.getType() === Account.TYPE_JAMI
+  const alias = isJamiAccount ? "Jami account" : "SIP account"
+  return (
+    <React.Fragment>
+      <Typography variant="h2" component="h2" gutterBottom>{alias}</Typography>
+      <Grid container spacing={3} style={{marginBottom: 16}}>
+        {isJamiAccount &&
+          <Grid item xs={12}><JamiIdCard account={account} /></Grid>}
+
+        <Grid item xs={12} sm={6}>
+          <ConversationsOverviewCard accountId={account.getId()} />
+        </Grid>
+
+        <Grid item xs={12} sm={6}>
+          <Card>
+            <CardContent>
+              <Typography className={classes.title} color="textSecondary" gutterBottom>
+                Current calls
+              </Typography>
+              <Typography gutterBottom variant="h5" component="h2">
+                0
+              </Typography>
+            </CardContent>
+          </Card>
+        </Grid>
+      </Grid>
+
+      <List subheader={<ListSubheader>Settings</ListSubheader>}>
+        <ListItem>
+          <ListItemIcon>
+            <GroupRounded />
+          </ListItemIcon>
+          <ListItemText id="switch-list-label-rendezvous" primary="Rendez-Vous point" />
+          <ListItemSecondaryAction>
+            <Switch
+              edge="end"
+              /*onChange={handleToggle('wifi')}*/
+              checked={account.isRendezVous()}
+              inputProps={{ 'aria-labelledby': 'switch-list-label-wifi' }}
+            />
+          </ListItemSecondaryAction>
+        </ListItem>
+        <ListItem>
+          <ListItemIcon>
+            <PhoneCallbackRounded />
+          </ListItemIcon>
+          <ListItemText id="switch-list-label-publicin" primary="Allow connection from unkown peers" />
+          <ListItemSecondaryAction>
+            <Switch
+              edge="end"
+              /*onChange={handleToggle('bluetooth')}*/
+              checked={account.isPublicIn()}
+              inputProps={{ 'aria-labelledby': 'switch-list-label-bluetooth' }}
+            />
+          </ListItemSecondaryAction>
+        </ListItem>
+      </List>
+
+
+
+
+
+    </React.Fragment>)
+}
diff --git a/client/src/components/ConversationAvatar.js b/client/src/components/ConversationAvatar.js
new file mode 100644
index 0000000..b9160a1
--- /dev/null
+++ b/client/src/components/ConversationAvatar.js
@@ -0,0 +1,7 @@
+import React from 'react';
+import { Avatar } from '@material-ui/core';
+import { PersonRounded } from '@material-ui/icons'
+
+export default function ConversationAvatar(props) {
+  return <Avatar>{props.displayName ? props.displayName[0].toUpperCase() : <PersonRounded />}</Avatar>
+}
diff --git a/client/src/components/ConversationList.js b/client/src/components/ConversationList.js
index b28a6d6..9fa4650 100644
--- a/client/src/components/ConversationList.js
+++ b/client/src/components/ConversationList.js
@@ -3,7 +3,7 @@
 import ConversationListItem from './ConversationListItem'
 import ListSubheader from '@material-ui/core/ListSubheader';
 import Conversation from '../../../model/Conversation';
-import GroupRoundedIcon from '@material-ui/icons/GroupRounded';
+import { GroupRounded as GroupIcon } from '@material-ui/icons';
 import Typography from '@material-ui/core/Typography';
 
 export default function ConversationList(props) {
@@ -21,7 +21,7 @@
                 )}
                 {props.conversations.length === 0 && (
                     <div className="list-placeholder">
-                        <GroupRoundedIcon color="disabled" fontSize="large"  />
+                        <GroupIcon color="disabled" fontSize="large"  />
                         <Typography className="subtitle" variant="subtitle2">No conversation yet</Typography>
                     </div>
                 )}
diff --git a/client/src/components/ConversationListItem.js b/client/src/components/ConversationListItem.js
index a769168..a0295d5 100644
--- a/client/src/components/ConversationListItem.js
+++ b/client/src/components/ConversationListItem.js
@@ -1,15 +1,14 @@
-import { Avatar, ListItem, ListItemAvatar, ListItemText } from '@material-ui/core'
+import { ListItem, ListItemAvatar, ListItemText } from '@material-ui/core'
 import React from 'react'
 import Conversation from '../../../model/Conversation'
 import { useHistory, useParams } from "react-router-dom"
-import { PersonRounded } from '@material-ui/icons'
+import ConversationAvatar from './ConversationAvatar'
 
 export default function ConversationListItem(props) {
     const { conversationId, contactId } = useParams()
     const conversation = props.conversation
     const pathId = conversationId || contactId
     const isSelected = conversation.getDisplayUri() === pathId
-    const displayName = conversation.getDisplayName()
     const history = useHistory()
 
     const uri = conversation.getId() ? `conversation/${conversation.getId()}` : `addContact/${conversation.getFirstMember().contact.getUri()}`
@@ -20,10 +19,8 @@
                 alignItems="flex-start"
                 selected={isSelected}
                 style={{overflow:'hidden'}}
-                onClick={() => history.push(`/account/${conversation.getAccountId()}/${uri}`)}>
-                <ListItemAvatar>
-                    <Avatar>{displayName ? displayName[0].toUpperCase() : <PersonRounded />}</Avatar>
-                </ListItemAvatar>
+                onClick={() => history.replace(`/account/${conversation.getAccountId()}/${uri}`)}>
+                <ListItemAvatar><ConversationAvatar displayName={conversation.getDisplayNameNoFallback()} /></ListItemAvatar>
                 <ListItemText
                     style={{overflow:'hidden', textOverflow:'ellipsis'}}
                     primary={conversation.getDisplayName()} secondary={conversation.getDisplayUri()} />
diff --git a/client/src/components/ConversationView.js b/client/src/components/ConversationView.js
index 678aafe..e818ba0 100644
--- a/client/src/components/ConversationView.js
+++ b/client/src/components/ConversationView.js
@@ -4,6 +4,7 @@
 import SendMessageForm from './SendMessageForm';
 import authManager from '../AuthManager'
 import Conversation from '../../../model/Conversation';
+import LoadingPage from './loading';
 
 class ConversationView extends React.Component {
     constructor(props) {
@@ -69,7 +70,7 @@
 
     render() {
         if (this.state.loaded === false) {
-            return <CircularProgress />
+            return <LoadingPage />
         } else if (this.state.error === true) {
             return <div>Error loding {this.props.conversationId}</div>
         } else {
diff --git a/client/src/components/ConversationsOverviewCard.js b/client/src/components/ConversationsOverviewCard.js
new file mode 100644
index 0000000..01b2d7b
--- /dev/null
+++ b/client/src/components/ConversationsOverviewCard.js
@@ -0,0 +1,47 @@
+import React, { useEffect, useState } from 'react';
+import { Box, Card, CardActionArea, CardContent, CircularProgress, Typography } from '@material-ui/core';
+import { makeStyles } from '@material-ui/core/styles';
+import { useHistory, useParams } from 'react-router';
+import authManager from '../AuthManager'
+import Conversation from '../../../model/Conversation';
+
+const useStyles = makeStyles({
+  title: {
+    fontSize: 14,
+  }, pos: {
+    fontSize: 14,
+  }
+});
+
+export default function ConversationsOverviewCard(props) {
+  const classes = useStyles()
+  const history = useHistory()
+  const accountId = props.accountId || useParams().accountId
+  const [state, setState] = useState({ loaded: false })
+
+  useEffect(() => {
+    const controller = new AbortController()
+    authManager.fetch(`/api/accounts/${accountId}/conversations`, { signal: controller.signal })
+      .then(res => res.json())
+      .then(result => {
+        console.log(result)
+        setState({ loaded: true, conversations: Object.values(result).map(c => Conversation.from(accountId, c)) })
+      })
+    return () => controller.abort()
+  }, [])
+
+  return (
+    <Card onClick={() => history.push(`/account/${accountId}`)} >
+      <CardActionArea>
+        <CardContent>
+          <Typography className={classes.title} color="textSecondary" gutterBottom>
+            Conversations
+          </Typography>
+          <Typography gutterBottom variant="h5" component="h2">
+            {state.loaded ? state.conversations.length : <CircularProgress size={24} />}
+          </Typography>
+        </CardContent>
+      </CardActionArea>
+    </Card>
+  )
+}
diff --git a/client/src/components/Header.js b/client/src/components/Header.js
index c0408a1..c621b56 100644
--- a/client/src/components/Header.js
+++ b/client/src/components/Header.js
@@ -1,45 +1,33 @@
-import React from 'react'
-import Button from '@material-ui/core/Button';
-import Menu from '@material-ui/core/Menu';
-import MenuItem from '@material-ui/core/MenuItem';
-//import { useHistory } from "react-router-dom";
+import React, { useState } from 'react'
+import { Box, Button, Menu, MenuItem } from '@material-ui/core'
+import { useHistory, useParams } from "react-router-dom"
 import authManager from '../AuthManager'
 
 export default function Header() {
-    //const history = useHistory();
+  const history = useHistory()
+  const [anchorEl, setAnchorEl] = useState(null)
+  const handleClick = (event) => setAnchorEl(event.currentTarget)
+  const handleClose = () => setAnchorEl(null)
+  const params = useParams()
 
-    const [anchorEl, setAnchorEl] = React.useState(null);
+  const goToAccountSelection = () => history.push(`/account`)
+  const goToAccountSettings = () => history.push(`/account/${params.accountId}/settings`)
 
-    const handleClick = (event) => {
-        setAnchorEl(event.currentTarget);
-    };
-
-    const handleClose = () => {
-        setAnchorEl(null);
-    };
-
-    const disconnect = () => {
-        authManager.disconnect()
-        //let path = `/`;
-        //history.push(path);
-    }
-
-    return (
-        <div>
-            <Button aria-controls="simple-menu" aria-haspopup="true" onClick={handleClick}>
-                Menu
-            </Button>
-            <Menu
-                id="simple-menu"
-                anchorEl={anchorEl}
-
-                open={Boolean(anchorEl)}
-                onClose={handleClose}
-            >
-                <MenuItem onClick={handleClose}>Profile</MenuItem>
-                <MenuItem onClick={handleClose}>Mon compte</MenuItem>
-                <MenuItem onClick={disconnect}>Déconnexion</MenuItem>
-            </Menu>
-        </div>
-    );
+  return (
+    <Box>
+      <Button aria-controls="simple-menu" aria-haspopup="true" onClick={handleClick}>
+        Menu
+      </Button>
+      <Menu
+        id="simple-menu"
+        anchorEl={anchorEl}
+        open={Boolean(anchorEl)}
+        onClose={handleClose}
+      >
+        <MenuItem onClick={goToAccountSelection}>Change account</MenuItem>
+        {params.accountId && <MenuItem onClick={goToAccountSettings}>Account settings</MenuItem>}
+        <MenuItem onClick={() => authManager.disconnect()}>Log out</MenuItem>
+      </Menu>
+      </Box>
+  )
 }
\ No newline at end of file
diff --git a/client/src/components/JamiIdCard.js b/client/src/components/JamiIdCard.js
index eb31a26..1b75bc5 100644
--- a/client/src/components/JamiIdCard.js
+++ b/client/src/components/JamiIdCard.js
@@ -1,25 +1,35 @@
 import React from 'react';
+import { Box, Card, CardContent, Typography } from '@material-ui/core';
+import { makeStyles } from '@material-ui/core/styles';
 
-import Card from '@material-ui/core/Card';
-import CardContent from '@material-ui/core/CardContent';
-import Typography from '@material-ui/core/Typography';
+const useStyles = makeStyles({
+  title: {
+    fontSize: 14,
+  }, pos: {
+    fontSize: 14,
 
-class JamiIdCard extends React.Component {
-  render() {
-    const account = this.props.account
-    const registeredName = account.getRegisteredName()
-    return (
-        <Card style={{marginBottom:16}}>
-          <CardContent>
-            <Typography variant="h6">Jami key ID</Typography>
-            <Typography variant="body1">{account.getUri()}</Typography>
-            {registeredName && <div>
-                <Typography variant="h6">Jami username</Typography>
-                <Typography variant="body1">{registeredName}</Typography></div>
-            }
-          </CardContent>
-        </Card>)
   }
-}
+});
 
-export default JamiIdCard;
\ No newline at end of file
+export default function JamiIdCard(props) {
+  const classes = useStyles()
+  const account = props.account
+  const registeredName = account.getRegisteredName()
+  return <Card style={{marginBottom:16}}>
+      <CardContent>
+        <Box>
+        <Typography className={classes.title} color="textSecondary">
+          Jami ID
+        </Typography>
+          <Typography variant="h5" component="h2" gutterBottom noWrap>{account.getUri()}</Typography>
+        </Box>
+        {registeredName && <Box>
+          <Typography className={classes.title} color="textSecondary" >
+          Jami username
+        </Typography>
+            <Typography variant="h5" component="h2" noWrap>{registeredName}</Typography>
+          </Box>
+        }
+      </CardContent>
+    </Card>
+}
diff --git a/client/src/components/MessageList.js b/client/src/components/MessageList.js
index 4841ea1..1673a38 100644
--- a/client/src/components/MessageList.js
+++ b/client/src/components/MessageList.js
@@ -1,26 +1,26 @@
 import Message from './Message'
 import React from 'react'
-import { Avatar, Box, Divider, Typography } from '@material-ui/core'
-import { PersonRounded } from '@material-ui/icons'
+import { Box, Divider, Typography } from '@material-ui/core'
+import ConversationAvatar from './ConversationAvatar'
 
 export default function MessageList(props) {
-    const displayName = props.conversation.getDisplayName()
+  const displayName = props.conversation.getDisplayName()
 
-    return (
-        <div className="message-list">
-            <Box>
-                <Box style={{ display: 'inline-block', margin: 16, verticalAlign: 'middle' }}>
-                    <Avatar>{displayName ? displayName[0].toUpperCase() : <PersonRounded />}</Avatar>
-                </Box>
-                <Box style={{ display: 'inline-block', verticalAlign: 'middle' }}>
-                    <Typography variant="h5">{displayName}</Typography>
-                    <Typography variant="subtitle1">{props.conversation.getId()}</Typography>
-                </Box>
-            </Box>
-            <Divider orientation="horizontal" />
-            {props.messages.map((message, index) =>
-                <Message key={index} username={message.senderId} text={message.text} />
-            )}
-        </div>
-    )
+  return (
+    <div className="message-list">
+      <Box>
+        <Box style={{ display: 'inline-block', margin: 16, verticalAlign: 'middle' }}>
+          <ConversationAvatar displayName={props.conversation.getDisplayNameNoFallback()} />
+        </Box>
+        <Box style={{ display: 'inline-block', verticalAlign: 'middle' }}>
+          <Typography variant="h6">{displayName}</Typography>
+          <Typography variant="subtitle1">{props.conversation.getId()}</Typography>
+        </Box>
+      </Box>
+      <Divider orientation="horizontal" />
+      {props.messages.map((message, index) =>
+        <Message key={index} username={message.senderId} text={message.text} />
+      )}
+    </div>
+  )
 }
\ No newline at end of file
diff --git a/client/src/components/NewContactForm.js b/client/src/components/NewContactForm.js
index 5636be2..3543d6d 100644
--- a/client/src/components/NewContactForm.js
+++ b/client/src/components/NewContactForm.js
@@ -1,49 +1,32 @@
-import React from 'react'
+import React, { useState } from 'react'
 import { InputBase, InputAdornment } from '@material-ui/core';
 import { SearchRounded } from '@material-ui/icons';
 
-class NewContactForm extends React.Component {
-    constructor(props) {
-        super(props)
-        this.state = {value: ''}
-        this.controller = new AbortController()
-        this.handleChange = this.handleChange.bind(this)
-        this.handleSubmit = this.handleSubmit.bind(this)
+export default function NewContactForm(props) {
+    const [value, setValue] = useState('')
+
+    const handleChange = event => {
+        setValue(event.target.value)
+        if (props.onChange)
+            props.onChange(event.target.value)
     }
 
-    componentDidMount() {
-        this.controller = new AbortController()
-    }
-
-    componentWillUnmount() {
-        this.controller.abort()
-        this.req = undefined
-    }
-
-    handleChange(event) {
-        this.setState({value: event.target.value})
-        this.props.onChange(event.target.value)
-    }
-
-    handleSubmit(event) {
+    const handleSubmit = event => {
         event.preventDefault()
-        if (this.props.onSubmit)
-            this.props.onSubmit(this.state.value)
+        if (value && props.onSubmit)
+            props.onSubmit(value)
     }
 
-    render() {
-        return (
-            <form className="main-search" onSubmit={this.handleSubmit} noValidate autoComplete="off">
-                <InputBase
-                    className="main-search-input"
-                    type="search"
-                    placeholder="Ajouter un contact"
-                    onChange={this.handleChange}
-                    startAdornment={<InputAdornment position="start"><SearchRounded /></InputAdornment>}
-                />
-            </form>
-        )
-    }
+    return (
+        <form className="main-search" onSubmit={handleSubmit} noValidate autoComplete="off">
+            <InputBase
+                className="main-search-input"
+                type="search"
+                placeholder="Ajouter un contact"
+                value={value}
+                onChange={handleChange}
+                startAdornment={<InputAdornment position="start"><SearchRounded /></InputAdornment>}
+            />
+        </form>
+    )
 }
-
-export default NewContactForm
\ No newline at end of file
diff --git a/client/src/components/loading.js b/client/src/components/loading.js
new file mode 100644
index 0000000..198b993
--- /dev/null
+++ b/client/src/components/loading.js
@@ -0,0 +1,8 @@
+import { CircularProgress, Container } from '@material-ui/core';
+import React from 'react';
+
+export default function LoadingPage() {
+    return <Container style={{ textAlign: "center" }}>
+        <CircularProgress style={{ margin: 32 }} />
+    </Container>
+}
\ No newline at end of file