Skip to content

Commit

Permalink
Merge pull request #202 from cityofaustin/4798-sg-avatar
Browse files Browse the repository at this point in the history
User Management | Implement default avatars #4798
  • Loading branch information
sergiogcx authored Feb 10, 2021
2 parents 78a7f02 + 9c0d1a0 commit 53dbb16
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 19 deletions.
40 changes: 40 additions & 0 deletions moped-editor/src/auth/user.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import React from "react";
import Amplify, { Auth } from "aws-amplify";

import { colors } from "@material-ui/core";

// Create a context that will hold the values that we are going to expose to our components.
// Don't worry about the `null` value. It's gonna be *instantly* overriden by the component below
export const UserContext = React.createContext(null);
Expand Down Expand Up @@ -80,6 +82,9 @@ export const UserProvider = ({ children }) => {
return data;
});

// Remove the current color
destroyProfileColor();

// Make sure to not force a re-render on the components that are reading these values,
// unless the `user` value has changed. This is an optimisation that is mostly needed in cases
// where the parent of the current component re-renders and thus the current component is forced
Expand All @@ -95,11 +100,46 @@ export const UserProvider = ({ children }) => {
return <UserContext.Provider value={values}>{children}</UserContext.Provider>;
};

/**
* This is a constant string key that holds the profile color for a user.
* @type {string}
* @variable
*/
export const atdColorKeyName = "atd_moped_user_color";

/**
* Returns a random themes standard color as hexadecimal
* @return {string}
*/
export const getRandomColor = () => {
if (localStorage.getItem(atdColorKeyName) === null) {
const randomInt = Math.floor(Math.random() * Math.floor(3));
const colorList = [
colors.green[900],
colors.indigo[600],
colors.orange[600],
colors.red[600],
];
localStorage.setItem(atdColorKeyName, colorList[randomInt]);
}
return localStorage.getItem(atdColorKeyName);
};

/**
* Removes the current user profile color
*/
export const destroyProfileColor = () => {
localStorage.removeItem(atdColorKeyName);
};

// We also create a simple custom hook to read these values from. We want our React components
// to know as little as possible on how everything is handled, so we are not only abtracting them from
// the fact that we are using React's context, but we also skip some imports.
export const useUser = () => {
const context = React.useContext(UserContext);
if (context && context.user) {
context.user.userColor = getRandomColor();
}

if (context === undefined) {
throw new Error(
Expand Down
34 changes: 26 additions & 8 deletions moped-editor/src/layouts/DashboardLayout/TopBar.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import MenuIcon from "@material-ui/icons/Menu";
import { LogOut as LogOutIcon } from "react-feather";
import Logo from "src/components/Logo";
import { useUser } from "../../auth/user";
import { defaultUser } from "../../views/account/AccountView/Profile";

const useStyles = makeStyles(() => ({
root: {},
Expand All @@ -26,7 +25,21 @@ const useStyles = makeStyles(() => ({

const TopBar = ({ className, onMobileNavOpen, ...rest }) => {
const classes = useStyles();
const { logout } = useUser();
const { user, logout } = useUser();

const emailToInitials = email => {
try {
const subdomain = "austintexas.gov";
if (!email.endsWith(subdomain)) return null;
const [first, last] = email
.replace("azure_ad", "")
.replace(subdomain, "")
.split(".");
return String(first.charAt(0) + last.charAt(0)).toUpperCase();
} catch {
return null;
}
};

return (
<AppBar className={clsx(classes.root, className)} elevation={0} {...rest}>
Expand All @@ -36,12 +49,17 @@ const TopBar = ({ className, onMobileNavOpen, ...rest }) => {
</RouterLink>
<Box flexGrow={1} />
<Box>
<Avatar
className={classes.avatar}
component={RouterLink}
src={defaultUser.avatar}
to="/moped/account"
/>
<div className={classes.root}>
<Avatar
className={classes.avatar}
component={RouterLink}
src={null}
to="/moped/account"
style={{ "background-color": user ? user.userColor : null }}
>
{emailToInitials(user.attributes.email)}
</Avatar>
</div>
</Box>
<Hidden mdDown>
<IconButton color="inherit" onClick={logout}>
Expand Down
21 changes: 10 additions & 11 deletions moped-editor/src/views/account/AccountView/Profile.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,7 @@ import {
Typography,
makeStyles,
} from "@material-ui/core";

export const defaultUser = {
avatar: `${process.env.PUBLIC_URL}/static/images/avatars/robSpillar.jpeg`,
name: "Rob Spillar",
jobTitle: "Director of Transportation",
city: "Austin, TX",
};
import { useUser } from "../../../auth/user";

const useStyles = makeStyles(() => ({
root: {},
Expand All @@ -31,22 +25,27 @@ const useStyles = makeStyles(() => ({

const Profile = ({ className, ...rest }) => {
const classes = useStyles();
const { user } = useUser();

return (
<Card className={clsx(classes.root, className)} {...rest}>
<CardContent>
<Box alignItems="center" display="flex" flexDirection="column">
<Box>
<Avatar className={classes.avatar} src={defaultUser.avatar} />
<Avatar
className={classes.avatar}
src={user?.userAvatar}
style={{ "background-color": user?.userColor }}
/>
</Box>
<Typography color="textPrimary" gutterBottom variant="h3">
{defaultUser.name}
{String(user?.userName ?? user?.attributes?.email).toLowerCase()}
</Typography>
<Typography color="textSecondary" variant="body1">
{defaultUser.jobTitle}
{user?.userJobTitle ?? "Austin Transportation"}
</Typography>
<Typography color="textSecondary" variant="body1">
{defaultUser.city}
{user?.userCity ?? "Austin, TX"}
</Typography>
</Box>
</CardContent>
Expand Down

0 comments on commit 53dbb16

Please sign in to comment.