Skip to content

Commit

Permalink
Text Avatar Play (reactplay#606)
Browse files Browse the repository at this point in the history
* Text Avatar

* Update src/plays/text-avatar/Readme.md

Co-authored-by: Sachin Chaurasiya <[email protected]>

* update based on change request

Co-authored-by: Sachin Chaurasiya <[email protected]>
Co-authored-by: Tapas Adhikary <[email protected]>
  • Loading branch information
3 people committed Oct 8, 2022
1 parent 7ee0bf0 commit eb5b54a
Show file tree
Hide file tree
Showing 12 changed files with 243 additions and 0 deletions.
21 changes: 21 additions & 0 deletions src/plays/text-avatar/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Text Avatar

Avatar based on the user's firstname and lastname with random background color

## Play Demographic

- Language: TypeScript
- Level: Beginner

## Creator Information

- User: hiimnhan
- Github Link: https://github.com/hiimnhan
- Blog: null

## What will you learn?

- Functional Component.
- Custom hook to fetch user from API
- useReducer hook
- Typescript basic
20 changes: 20 additions & 0 deletions src/plays/text-avatar/TextAvatar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from 'react';
import UserCard from './components/UserCard';
import { API_URL } from './constants';
import { useFetchUser } from './hooks/useFetchUser';
import './style.scss';

function TextAvatar() {
const { users } = useFetchUser({ url: API_URL});
return (
<div className='text-avatar_container'>
{
users.map((user, index) => (
<UserCard name={user.name} key={index} />
))
}
</div>
)
}

export default TextAvatar;
20 changes: 20 additions & 0 deletions src/plays/text-avatar/components/Avatar/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { AvatarProps } from 'plays/text-avatar/types';
import React from 'react';
import { generateAbbreName, getRandomColor } from '../../utils';
import './style.scss';

function Avatar({first, last}: AvatarProps) {
const randomColor = getRandomColor();
const abbreName = generateAbbreName(first, last);

return (
<div className='text-avatar_avatar'
style={{
backgroundColor: randomColor,
}}>
{abbreName}
</div>
)
}

export default Avatar;
10 changes: 10 additions & 0 deletions src/plays/text-avatar/components/Avatar/style.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.text-avatar_avatar {
width: 36px;
height: 36px;
border-radius: 50%;
padding: 0.5rem;
display: flex;
justify-content: center;
align-items: center;
color: white;
}
16 changes: 16 additions & 0 deletions src/plays/text-avatar/components/UserCard/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from 'react';
import { User } from '../../types';
import Avatar from '../Avatar';
import './style.scss';

function UserCard({ name }: User) {
const { first, last } = name;
return (
<div className='text-avatar_card'>
<Avatar first={first} last={last} />
<p className='text-avatar_username'>{first} { last }</p>
</div>
)
}

export default UserCard;
18 changes: 18 additions & 0 deletions src/plays/text-avatar/components/UserCard/style.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
.text-avatar_card {
border: 1px solid #dcdce0;
padding: 1rem;
max-width: 200px;
min-width: 200px;
height: 150px;
border-radius: 0.5rem;
text-align: center;
display: flex;
flex-direction: column;
align-items: center ;
box-shadow: rgba(100, 100, 111, 0.2) 0px 7px 29px 0px;
& .text-avatar_username {
margin-top: 2rem;
font-weight: bold;
color: black;
}
}
1 change: 1 addition & 0 deletions src/plays/text-avatar/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const API_URL = 'https://randomuser.me/api/?inc=name&results=10';
Binary file added src/plays/text-avatar/cover.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
74 changes: 74 additions & 0 deletions src/plays/text-avatar/hooks/useFetchUser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import axios from 'axios';
import { useEffect, useReducer } from 'react';
import { ActionFailureReturnType, ActionRequestReturnType, ActionsReturnType, ActionSuccessReturnType, Arguments, State, User } from '../types';

const fetchUserSuccess = (users: User[]): ActionSuccessReturnType => ({
type: 'success',
payload: users
});

const fetchUserRequest = (): ActionRequestReturnType => ({
type: 'request',
payload: undefined
});

const fetchUserFailure = (error: any): ActionFailureReturnType => ({
type: 'failure',
payload: error
});

const initialState: State = {
users: [],
error: undefined,
fetching: false
};

function reducer(state: State, action: ActionsReturnType): State {
switch (action.type) {
case 'request':
return {
...state,
fetching: true
}
case 'success':
const users = action.payload as User[];
return {
...state,
users,
fetching: false
}
case 'failure':
const error = action.payload;
return {
...state,
fetching: false,
error
}
default:
return state;
}
};


export function useFetchUser({ url, options }: Arguments) {
const [state, dispatch] = useReducer(reducer, initialState);

useEffect(() => {
if (!url || url === '') return;
async function fetchUser() {
dispatch(fetchUserRequest());

try {
const response = await axios.get(url, options);
const { results } = response.data;
dispatch(fetchUserSuccess(results));
} catch (error) {
dispatch(fetchUserFailure(error));
}
}

fetchUser();
}, [url, options])

return state;
}
12 changes: 12 additions & 0 deletions src/plays/text-avatar/style.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.text-avatar_container {
align-self: center;
margin-top: 5rem;
display: flex;
flex-direction: row;
flex-wrap: wrap;
gap: 1.5rem;
justify-content: center;
background-color: #f3f4fa;
width: 100%;
height: 50vh;
}
39 changes: 39 additions & 0 deletions src/plays/text-avatar/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
export type User = {
name: {
first: string;
last: string;
}
};
export type AvatarProps = {
first: string;
last: string;
}

export type State = {
users: User[],
error?: any,
fetching: boolean
};
export type ActionType = 'request' | 'success' | 'failure';
export type ActionReturnType<T> = {
type: ActionType,
payload: T
}
export type ActionSuccessReturnType = ActionReturnType<User[]>;


export type ActionRequestReturnType = ActionReturnType<undefined>;


export type ActionFailureReturnType = ActionReturnType<any>;


export type ActionsReturnType =
| ActionRequestReturnType
| ActionSuccessReturnType
| ActionFailureReturnType;

export type Arguments = {
url: string,
options?: any
}
12 changes: 12 additions & 0 deletions src/plays/text-avatar/utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export function getRandomColor() {
var letters = '0123456789ABCDEF';
var color = '#';
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}

export function generateAbbreName(first: string, last: string): string {
return `${first[0]}${last[0]}`;
}

0 comments on commit eb5b54a

Please sign in to comment.