User profile page
parent
7cd40357ab
commit
b617d59b69
4
.env
4
.env
|
@ -1,6 +1,6 @@
|
||||||
#REACT_APP_TUITIO_URL=http://localhost:5063/identity/authenticate?UserName={username}&Password={password}
|
#REACT_APP_TUITIO_URL=http://localhost:5063
|
||||||
|
|
||||||
REACT_APP_TUITIO_URL=https://lab.code-rove.com/tuitio
|
REACT_APP_TUITIO_URL=https://lab.code-rove.com/tuitio
|
||||||
|
|
||||||
#REACT_APP_NETWORK_RESURRECTOR_API_URL=http://localhost:5064
|
#REACT_APP_NETWORK_RESURRECTOR_API_URL=http://localhost:5064
|
||||||
REACT_APP_NETWORK_RESURRECTOR_API_URL=https://lab.code-rove.com/network-resurrector-api
|
REACT_APP_NETWORK_RESURRECTOR_API_URL=https://lab.code-rove.com/network-resurrector-api
|
||||||
|
|
||||||
|
|
|
@ -12,9 +12,16 @@
|
||||||
"English": "English",
|
"English": "English",
|
||||||
"Romanian": "Romanian"
|
"Romanian": "Romanian"
|
||||||
},
|
},
|
||||||
|
"Generic": {
|
||||||
|
"Copy": "Copy",
|
||||||
|
"OpenInNewTab": "Open in new tab",
|
||||||
|
"CopiedToClipboard": "Copied to clipboard",
|
||||||
|
"SendEmail": "Send email"
|
||||||
|
},
|
||||||
"Menu": {
|
"Menu": {
|
||||||
"Dashboard": "Dashboard",
|
"Dashboard": "Dashboard",
|
||||||
"Machines": "Machines",
|
"Machines": "Machines",
|
||||||
|
"System": "System",
|
||||||
"Trash": "Trash",
|
"Trash": "Trash",
|
||||||
"Settings": "Settings"
|
"Settings": "Settings"
|
||||||
},
|
},
|
||||||
|
@ -22,12 +29,15 @@
|
||||||
"Username": "Username",
|
"Username": "Username",
|
||||||
"Password": "Password",
|
"Password": "Password",
|
||||||
"Label": "Login",
|
"Label": "Login",
|
||||||
"ChangeUser": "Change user",
|
|
||||||
"UserChanged": "User changed",
|
|
||||||
"Logout": "Logout",
|
"Logout": "Logout",
|
||||||
"IncorrectCredentials": "Incorrect credentials.",
|
"IncorrectCredentials": "Incorrect credentials."
|
||||||
"Hello": "Hi, {{username}}",
|
},
|
||||||
"AuthenticationDate": "Authentication date"
|
"User": {
|
||||||
|
"Profile": {
|
||||||
|
"Hello": "Hi, {{userName}}",
|
||||||
|
"Description": "{{userName}}, authenticated on {{loginDate}}",
|
||||||
|
"OpenPortfolio": "Open portfolio"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"Machine": {
|
"Machine": {
|
||||||
"FullName": "Full machine name",
|
"FullName": "Full machine name",
|
||||||
|
|
|
@ -3,9 +3,16 @@
|
||||||
"English": "Engleză",
|
"English": "Engleză",
|
||||||
"Romanian": "Română"
|
"Romanian": "Română"
|
||||||
},
|
},
|
||||||
|
"Generic": {
|
||||||
|
"Copy": "Copiază",
|
||||||
|
"OpenInNewTab": "Deschide într-un tab nou",
|
||||||
|
"CopiedToClipboard": "Copiat în clipboard",
|
||||||
|
"SendEmail": "Trimite email"
|
||||||
|
},
|
||||||
"Menu": {
|
"Menu": {
|
||||||
"Dashboard": "Bord",
|
"Dashboard": "Bord",
|
||||||
"Machines": "Mașini",
|
"Machines": "Mașini",
|
||||||
|
"System": "Sistem",
|
||||||
"Trash": "Gunoi",
|
"Trash": "Gunoi",
|
||||||
"Settings": "Setări"
|
"Settings": "Setări"
|
||||||
},
|
},
|
||||||
|
@ -13,12 +20,15 @@
|
||||||
"Username": "Utilizator",
|
"Username": "Utilizator",
|
||||||
"Password": "Parolă",
|
"Password": "Parolă",
|
||||||
"Label": "Autentificare",
|
"Label": "Autentificare",
|
||||||
"ChangeUser": "Schimbă utilizatorul",
|
|
||||||
"UserChanged": "Utilizator schimbat",
|
|
||||||
"Logout": "Deconectare",
|
"Logout": "Deconectare",
|
||||||
"IncorrectCredentials": "Credențiale incorecte.",
|
"IncorrectCredentials": "Credențiale incorecte."
|
||||||
"Hello": "Salut, {{username}}",
|
},
|
||||||
"AuthenticationDate": "Momentul autentificării"
|
"User": {
|
||||||
|
"Profile": {
|
||||||
|
"Hello": "Salut, {{userName}}",
|
||||||
|
"Description": "{{userName}}, autentificat pe {{loginDate}}",
|
||||||
|
"OpenPortfolio": "Deschide portofoliu"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"Machine": {
|
"Machine": {
|
||||||
"FullName": "Nume intreg masina",
|
"FullName": "Nume intreg masina",
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 89 KiB |
|
@ -1,16 +1,16 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Route, Switch } from "react-router-dom";
|
import { Route, Switch } from "react-router-dom";
|
||||||
import PageNotFound from "./PageNotFound";
|
import PageNotFound from "./PageNotFound";
|
||||||
import LoginContainer from "../../features/login/components/LoginContainer";
|
|
||||||
import NetworkContainer from "../../features/network/components/NetworkContainer";
|
import NetworkContainer from "../../features/network/components/NetworkContainer";
|
||||||
import SettingsContainer from "../../features/settings/components/SettingsContainer";
|
import SettingsContainer from "../../features/settings/components/SettingsContainer";
|
||||||
import DashboardContainer from "../../features/dashboard/components/DashboardContainer";
|
import DashboardContainer from "../../features/dashboard/components/DashboardContainer";
|
||||||
|
import UserProfileContainer from "../../features/user/profile/components/UserProfileContainer";
|
||||||
|
|
||||||
const AppRoutes = () => {
|
const AppRoutes = () => {
|
||||||
return (
|
return (
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route exact path="/dashboard" component={DashboardContainer} />
|
<Route exact path="/dashboard" component={DashboardContainer} />
|
||||||
<Route exact path="/user-profile" component={LoginContainer} />
|
<Route exact path="/user-profile" component={UserProfileContainer} />
|
||||||
<Route exact path="/machines" component={NetworkContainer} />
|
<Route exact path="/machines" component={NetworkContainer} />
|
||||||
<Route exact path="/settings" component={SettingsContainer} />
|
<Route exact path="/settings" component={SettingsContainer} />
|
||||||
<Route component={PageNotFound} />
|
<Route component={PageNotFound} />
|
||||||
|
|
|
@ -15,6 +15,7 @@ import ChevronRightIcon from "@material-ui/icons/ChevronRight";
|
||||||
import ListItem from "@material-ui/core/ListItem";
|
import ListItem from "@material-ui/core/ListItem";
|
||||||
import DeleteIcon from "@material-ui/icons/Delete";
|
import DeleteIcon from "@material-ui/icons/Delete";
|
||||||
import DnsIcon from "@material-ui/icons/Dns";
|
import DnsIcon from "@material-ui/icons/Dns";
|
||||||
|
import DeviceHubIcon from "@material-ui/icons/DeviceHub";
|
||||||
import SettingsIcon from "@material-ui/icons/Settings";
|
import SettingsIcon from "@material-ui/icons/Settings";
|
||||||
import DashboardIcon from "@material-ui/icons/Dashboard";
|
import DashboardIcon from "@material-ui/icons/Dashboard";
|
||||||
import { useHistory } from "react-router-dom";
|
import { useHistory } from "react-router-dom";
|
||||||
|
@ -74,6 +75,12 @@ const Sidebar = ({ open, handleDrawerClose }) => {
|
||||||
</ListItemIcon>
|
</ListItemIcon>
|
||||||
<ListItemText primary={t("Menu.Machines")} />
|
<ListItemText primary={t("Menu.Machines")} />
|
||||||
</ListItem>
|
</ListItem>
|
||||||
|
<ListItem button key="system" onClick={() => history.push("/system")}>
|
||||||
|
<ListItemIcon>
|
||||||
|
<DeviceHubIcon />
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText primary={t("Menu.System")} />
|
||||||
|
</ListItem>
|
||||||
</List>
|
</List>
|
||||||
<Divider />
|
<Divider />
|
||||||
<List>
|
<List>
|
||||||
|
|
|
@ -1,111 +0,0 @@
|
||||||
import React, { useState, useMemo } from "react";
|
|
||||||
import PropTypes from "prop-types";
|
|
||||||
import { makeStyles } from "@material-ui/core/styles";
|
|
||||||
import {
|
|
||||||
Avatar,
|
|
||||||
Collapse,
|
|
||||||
Tooltip,
|
|
||||||
Divider,
|
|
||||||
Typography,
|
|
||||||
Card,
|
|
||||||
CardContent,
|
|
||||||
CardActions,
|
|
||||||
CardHeader,
|
|
||||||
IconButton
|
|
||||||
} from "@material-ui/core";
|
|
||||||
import { AccountBox, RotateLeft, ExitToApp } from "@material-ui/icons";
|
|
||||||
import LoginComponent from "./LoginComponent";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import { useToast } from "../../../hooks";
|
|
||||||
import styles from "../styles";
|
|
||||||
import { useTuitioUser } from "@flare/tuitio-client-react";
|
|
||||||
|
|
||||||
const useStyles = makeStyles(styles);
|
|
||||||
|
|
||||||
const LoggedInComponent = ({ credentials, onChange, onLogin, onLogout }) => {
|
|
||||||
const classes = useStyles();
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const [expanded, setExpanded] = useState(false);
|
|
||||||
const { info } = useToast();
|
|
||||||
const { userName } = useTuitioUser();
|
|
||||||
|
|
||||||
const handleExpandLogin = () => {
|
|
||||||
setExpanded(!expanded);
|
|
||||||
};
|
|
||||||
|
|
||||||
const loginDate = useMemo(() => {
|
|
||||||
const valueForDisplay = t("LONG_DATE", { date: new Date() });
|
|
||||||
return valueForDisplay;
|
|
||||||
}, [t]);
|
|
||||||
|
|
||||||
const handleLogin = async () => {
|
|
||||||
const result = await onLogin();
|
|
||||||
if (result) {
|
|
||||||
setExpanded(false);
|
|
||||||
info(t("Login.UserChanged"));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={classes.loggedInContent}>
|
|
||||||
<Card className={classes.loggedInCard}>
|
|
||||||
<CardHeader
|
|
||||||
avatar={
|
|
||||||
<Avatar aria-label="user" className={classes.avatar}>
|
|
||||||
<AccountBox />
|
|
||||||
</Avatar>
|
|
||||||
}
|
|
||||||
title={<strong>{t("Login.Hello", { username: userName })}</strong>}
|
|
||||||
subheader={
|
|
||||||
<Tooltip title={t("Login.AuthenticationDate")}>
|
|
||||||
<Typography variant="caption" display="block">
|
|
||||||
{loginDate}
|
|
||||||
</Typography>
|
|
||||||
</Tooltip>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<CardActions disableSpacing>
|
|
||||||
<Tooltip title={t("Login.ChangeUser")}>
|
|
||||||
<IconButton
|
|
||||||
size="small"
|
|
||||||
className={classes.onRight}
|
|
||||||
onClick={handleExpandLogin}
|
|
||||||
aria-expanded={expanded}
|
|
||||||
aria-label="show login component"
|
|
||||||
>
|
|
||||||
<RotateLeft />
|
|
||||||
</IconButton>
|
|
||||||
</Tooltip>
|
|
||||||
<Tooltip title={t("Login.Logout")}>
|
|
||||||
<IconButton size="small" onClick={onLogout}>
|
|
||||||
<ExitToApp />
|
|
||||||
</IconButton>
|
|
||||||
</Tooltip>
|
|
||||||
</CardActions>
|
|
||||||
<Divider />
|
|
||||||
<Collapse in={expanded} timeout="auto" unmountOnExit>
|
|
||||||
<CardContent
|
|
||||||
className={classes.collapseContent}
|
|
||||||
style={{ paddingBottom: "5px" }}
|
|
||||||
>
|
|
||||||
<LoginComponent
|
|
||||||
credentials={credentials}
|
|
||||||
onChange={onChange}
|
|
||||||
onLogin={handleLogin}
|
|
||||||
/>
|
|
||||||
</CardContent>
|
|
||||||
</Collapse>
|
|
||||||
</Card>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
LoggedInComponent.propTypes = {
|
|
||||||
credentials: PropTypes.object.isRequired,
|
|
||||||
onChange: PropTypes.func.isRequired,
|
|
||||||
onLogin: PropTypes.func.isRequired,
|
|
||||||
onLogout: PropTypes.func.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
export default LoggedInComponent;
|
|
|
@ -2,8 +2,7 @@ import React, { useState } from "react";
|
||||||
import LoginCard from "./LoginCard";
|
import LoginCard from "./LoginCard";
|
||||||
import { useToast } from "../../../hooks";
|
import { useToast } from "../../../hooks";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import LoggedInComponent from "./LoggedInComponent";
|
import { useTuitioClient } from "@flare/tuitio-client-react";
|
||||||
import { useTuitioClient, useTuitioToken } from "@flare/tuitio-client-react";
|
|
||||||
|
|
||||||
const LoginContainer = () => {
|
const LoginContainer = () => {
|
||||||
const [credentials, setCredentials] = useState({
|
const [credentials, setCredentials] = useState({
|
||||||
|
@ -13,11 +12,10 @@ const LoginContainer = () => {
|
||||||
|
|
||||||
const { error } = useToast();
|
const { error } = useToast();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { login, logout } = useTuitioClient({
|
const { login } = useTuitioClient({
|
||||||
onLoginFailed: () => error(t("Login.IncorrectCredentials")),
|
onLoginFailed: () => error(t("Login.IncorrectCredentials")),
|
||||||
onLoginError: err => error(err.message)
|
onLoginError: err => error(err.message)
|
||||||
});
|
});
|
||||||
const { valid: tokenIsValid } = useTuitioToken();
|
|
||||||
|
|
||||||
const handleChange = prop => event => {
|
const handleChange = prop => event => {
|
||||||
setCredentials(prev => ({ ...prev, [prop]: event.target.value }));
|
setCredentials(prev => ({ ...prev, [prop]: event.target.value }));
|
||||||
|
@ -28,27 +26,12 @@ const LoginContainer = () => {
|
||||||
return login(userName, password);
|
return login(userName, password);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleLogout = () => {
|
|
||||||
logout();
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
|
||||||
{tokenIsValid ? (
|
|
||||||
<LoggedInComponent
|
|
||||||
credentials={credentials}
|
|
||||||
onChange={handleChange}
|
|
||||||
onLogin={handleLogin}
|
|
||||||
onLogout={handleLogout}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<LoginCard
|
<LoginCard
|
||||||
credentials={credentials}
|
credentials={credentials}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
onLogin={handleLogin}
|
onLogin={handleLogin}
|
||||||
/>
|
/>
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,23 +1,7 @@
|
||||||
const styles = theme => ({
|
const styles = theme => ({
|
||||||
loggedInCard: {
|
|
||||||
minWidth: 350
|
|
||||||
},
|
|
||||||
onRight: {
|
onRight: {
|
||||||
marginLeft: "auto"
|
marginLeft: "auto"
|
||||||
},
|
},
|
||||||
avatar: {
|
|
||||||
backgroundColor: theme.palette.primary.main
|
|
||||||
},
|
|
||||||
collapseContent: {
|
|
||||||
padding: 0
|
|
||||||
},
|
|
||||||
loggedInContent: {
|
|
||||||
minHeight: "80vh",
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "center",
|
|
||||||
fontSize: "calc(10px + 2vmin)"
|
|
||||||
},
|
|
||||||
appLogin: {
|
appLogin: {
|
||||||
minHeight: "100vh",
|
minHeight: "100vh",
|
||||||
display: "flex",
|
display: "flex",
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import MachinesContainer from "../../machines/components/MachinesContainer";
|
import MachinesContainer from "../../machines/components/MachinesContainer";
|
||||||
//import NotesContainer from "../../notes/components/NotesContainer";
|
|
||||||
import { makeStyles } from "@material-ui/core/styles";
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
import styles from "../styles";
|
import styles from "../styles";
|
||||||
|
|
||||||
|
@ -12,7 +11,6 @@ const NetworkContainer = () => {
|
||||||
return (
|
return (
|
||||||
<div className={classes.root}>
|
<div className={classes.root}>
|
||||||
<MachinesContainer />
|
<MachinesContainer />
|
||||||
{/* <NotesContainer /> */}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
import React, { useContext } from "react";
|
|
||||||
import { TextField, Button } from "@material-ui/core";
|
|
||||||
import {
|
|
||||||
ApplicationStateContext,
|
|
||||||
ApplicationDispatchContext
|
|
||||||
} from "../../../state/ApplicationContexts";
|
|
||||||
|
|
||||||
const NotesContainer = () => {
|
|
||||||
const state = useContext(ApplicationStateContext);
|
|
||||||
const dispatchActions = useContext(ApplicationDispatchContext);
|
|
||||||
|
|
||||||
const handleChange = prop => event => {
|
|
||||||
dispatchActions.onNetworkChange(prop, event.target.value);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<TextField
|
|
||||||
id="ertet"
|
|
||||||
label="Test"
|
|
||||||
onChange={handleChange("test")}
|
|
||||||
value={state.network.test}
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<Button variant="contained" color="primary">
|
|
||||||
Read machines
|
|
||||||
</Button>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default NotesContainer;
|
|
|
@ -0,0 +1,112 @@
|
||||||
|
import React from "react";
|
||||||
|
import PropTypes from "prop-types";
|
||||||
|
import {
|
||||||
|
Grid,
|
||||||
|
List,
|
||||||
|
ListItem,
|
||||||
|
ListItemText,
|
||||||
|
ListItemIcon,
|
||||||
|
Link,
|
||||||
|
IconButton,
|
||||||
|
Tooltip
|
||||||
|
} from "@material-ui/core";
|
||||||
|
import UserProfilePicture from "./UserProfilePicture";
|
||||||
|
import BusinessCenterIcon from "@material-ui/icons/BusinessCenter";
|
||||||
|
import { FileCopyOutlined } from "@material-ui/icons";
|
||||||
|
import EmailIcon from "@material-ui/icons/Email";
|
||||||
|
import { useToast } from "../../../../hooks";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
|
const UserProfileCardContent = ({ userData }) => {
|
||||||
|
const { email, profilePictureUrl } = userData;
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { info } = useToast();
|
||||||
|
|
||||||
|
const handleCopyToClipboard = url => () => {
|
||||||
|
navigator.clipboard.writeText(url);
|
||||||
|
info(t("Generic.CopiedToClipboard"));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleEmailSending = event => {
|
||||||
|
window.location.href = `mailto:${email}`;
|
||||||
|
event.preventDefault();
|
||||||
|
};
|
||||||
|
|
||||||
|
const userName = `${userData.firstName} ${userData.lastName}`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Grid container spacing={2}>
|
||||||
|
<Grid item xs={12} sm={4} lg={2}>
|
||||||
|
<UserProfilePicture userData={userData} />
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12} sm={8} lg={10}>
|
||||||
|
<Grid container spacing={2}>
|
||||||
|
<Grid item xs={12} sm={6}>
|
||||||
|
<List>
|
||||||
|
<ListItem dense>
|
||||||
|
<ListItemIcon>
|
||||||
|
<BusinessCenterIcon />
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText
|
||||||
|
primary={
|
||||||
|
<Tooltip title={t("User.Profile.OpenPortfolio")}>
|
||||||
|
<Link
|
||||||
|
href="https://lab.code-rove.com/tsp/"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
{userName}
|
||||||
|
</Link>
|
||||||
|
</Tooltip>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</ListItem>
|
||||||
|
<ListItem dense>
|
||||||
|
<ListItemIcon>
|
||||||
|
<EmailIcon />
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText
|
||||||
|
primary={
|
||||||
|
<Tooltip title={t("Generic.SendEmail")}>
|
||||||
|
<Link href="#" onClick={handleEmailSending}>
|
||||||
|
{email}
|
||||||
|
</Link>
|
||||||
|
</Tooltip>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</ListItem>
|
||||||
|
{profilePictureUrl && (
|
||||||
|
<ListItem dense>
|
||||||
|
<ListItemIcon>
|
||||||
|
<Tooltip title={t("Generic.Copy")}>
|
||||||
|
<IconButton
|
||||||
|
size="small"
|
||||||
|
onClick={handleCopyToClipboard(profilePictureUrl)}
|
||||||
|
>
|
||||||
|
<FileCopyOutlined />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText
|
||||||
|
primary={
|
||||||
|
<Tooltip title={t("Generic.OpenInNewTab")}>
|
||||||
|
<Link href={profilePictureUrl} target="_blank">
|
||||||
|
{profilePictureUrl}
|
||||||
|
</Link>
|
||||||
|
</Tooltip>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</ListItem>
|
||||||
|
)}
|
||||||
|
</List>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
UserProfileCardContent.propTypes = {
|
||||||
|
userData: PropTypes.object.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default UserProfileCardContent;
|
|
@ -0,0 +1,47 @@
|
||||||
|
import React, { useMemo } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { Card, CardHeader, CardContent } from "@material-ui/core";
|
||||||
|
import { useTuitioToken } from "@flare/tuitio-client-react";
|
||||||
|
import { camelizeKeys } from "../../../../utils/camelizeKeys";
|
||||||
|
import PageTitle from "../../../../components/common/PageTitle";
|
||||||
|
import UserProfileCardContent from "./UserProfileCardContent";
|
||||||
|
|
||||||
|
const UserProfileContainer = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { token } = useTuitioToken();
|
||||||
|
|
||||||
|
const decodedToken = useMemo(() => atob(token), [token]);
|
||||||
|
const userData = useMemo(
|
||||||
|
() => camelizeKeys(JSON.parse(decodedToken)),
|
||||||
|
[decodedToken]
|
||||||
|
);
|
||||||
|
console.log("userData", userData);
|
||||||
|
const userLoginDate = useMemo(
|
||||||
|
() =>
|
||||||
|
t("DATE_FORMAT", {
|
||||||
|
date: { value: userData.createdAt, format: "DD-MM-YYYY HH:mm:ss" }
|
||||||
|
}),
|
||||||
|
[t, userData.createdAt]
|
||||||
|
);
|
||||||
|
|
||||||
|
const userDescription = t("User.Profile.Description", {
|
||||||
|
userName: `${userData.firstName} ${userData.lastName}`,
|
||||||
|
loginDate: userLoginDate
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<PageTitle
|
||||||
|
text={t("User.Profile.Hello", { userName: userData.firstName })}
|
||||||
|
/>
|
||||||
|
<Card>
|
||||||
|
<CardHeader title={userData.userName} subheader={userDescription} />
|
||||||
|
<CardContent>
|
||||||
|
<UserProfileCardContent userData={userData} />
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default UserProfileContainer;
|
|
@ -0,0 +1,21 @@
|
||||||
|
import React from "react";
|
||||||
|
import PropTypes from "prop-types";
|
||||||
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
|
import style from "../styles";
|
||||||
|
import Avatar from "@material-ui/core/Avatar";
|
||||||
|
import DefaultUserProfilePicture from "../../../../assets/images/DefaultUserProfilePicture.png";
|
||||||
|
|
||||||
|
const useStyles = makeStyles(style);
|
||||||
|
|
||||||
|
const UserProfilePicture = ({ userData }) => {
|
||||||
|
const classes = useStyles();
|
||||||
|
const { profilePictureUrl } = userData;
|
||||||
|
const url = profilePictureUrl ?? DefaultUserProfilePicture;
|
||||||
|
return <Avatar src={url} alt="..." className={classes.profilePicture} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
UserProfilePicture.propTypes = {
|
||||||
|
userData: PropTypes.object.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default UserProfilePicture;
|
|
@ -0,0 +1,12 @@
|
||||||
|
const style = theme => {
|
||||||
|
return {
|
||||||
|
profilePicture: {
|
||||||
|
margin: "auto",
|
||||||
|
display: "block",
|
||||||
|
width: theme.spacing(25),
|
||||||
|
height: theme.spacing(25)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default style;
|
|
@ -0,0 +1,31 @@
|
||||||
|
function camelizeKeys(o) {
|
||||||
|
var newO, origKey, newKey, value;
|
||||||
|
if (o instanceof Array) {
|
||||||
|
return o.map(function (value) {
|
||||||
|
if (typeof value === "object") {
|
||||||
|
value = camelizeKeys(value);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
newO = {};
|
||||||
|
for (origKey in o) {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(o, origKey)) {
|
||||||
|
newKey = (
|
||||||
|
origKey.charAt(0).toLowerCase() + origKey.slice(1) || origKey
|
||||||
|
).toString();
|
||||||
|
value = o[origKey];
|
||||||
|
if (
|
||||||
|
value instanceof Array ||
|
||||||
|
(value !== null && value.constructor === Object)
|
||||||
|
) {
|
||||||
|
value = camelizeKeys(value);
|
||||||
|
}
|
||||||
|
newO[newKey] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newO;
|
||||||
|
}
|
||||||
|
|
||||||
|
export { camelizeKeys };
|
Loading…
Reference in New Issue