forked from paypay/FullStackEngineerChallenge
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* refactor: Button * implement EmployeeList * add api: get review list * implement ReviewList
- Loading branch information
1 parent
343bf0c
commit 1b8aa75
Showing
26 changed files
with
646 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { oneOf } from 'prop-types'; | ||
import styled from 'styled-components'; | ||
import { DANGER } from '@/styles/colors'; | ||
import { sizes } from '@/components/Button/utils'; | ||
|
||
const Badge = styled.div` | ||
${props => sizes(props.size)}; | ||
display: inline-block; | ||
margin: 0 8px; | ||
color: white; | ||
background-color: ${DANGER}; | ||
`; | ||
|
||
Badge.propTypes = { | ||
size: oneOf(['small', 'medium', 'large']), | ||
}; | ||
|
||
Badge.defaultProps = { | ||
size: 'medium', | ||
}; | ||
|
||
export default Badge; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import { bool, oneOf } from 'prop-types'; | ||
import styled, { css } from 'styled-components'; | ||
import { BLACK, LIGHT_BLACK } from '@/styles/colors'; | ||
import { sizes } from './utils'; | ||
|
||
const activeCSS = css` | ||
color: ${BLACK}; | ||
&:after { | ||
transform: scaleX(1); | ||
} | ||
`; | ||
|
||
const Tab = styled.button.attrs(() => ({ | ||
type: 'button', | ||
}))` | ||
${props => sizes(props.size)}; | ||
position: relative; | ||
border: none; | ||
outline: none; | ||
color: ${LIGHT_BLACK}; | ||
background-color: transparent; | ||
transition: color 0.3s ease-out; | ||
will-change: color; | ||
cursor: pointer; | ||
&:after { | ||
content: ''; | ||
display: block; | ||
width: 50%; | ||
height: 3px; | ||
position: relative; | ||
margin: 10px auto 0; | ||
background-color: ${BLACK}; | ||
transform: scaleX(0); | ||
transition: transform 0.15s ease-out; | ||
} | ||
&:hover, | ||
&:active { | ||
color: ${BLACK}; | ||
} | ||
${props => props.isActive && activeCSS}; | ||
`; | ||
|
||
Tab.propTypes = { | ||
size: oneOf(['small', 'medium', 'large']), | ||
isActive: bool, | ||
}; | ||
|
||
Tab.defaultProps = { | ||
size: 'medium', | ||
isActive: false, | ||
}; | ||
|
||
export default Tab; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,25 +1,38 @@ | ||
import React from 'react'; | ||
import { func } from 'prop-types'; | ||
import { string, oneOf } from 'prop-types'; | ||
import styled from 'styled-components'; | ||
import { BLACK } from '@/styles/colors'; | ||
import { sizes } from './utils'; | ||
|
||
const StyledButton = styled.button` | ||
${props => sizes(props.size)}; | ||
border: none; | ||
outline: none; | ||
color: ${props => props.color}; | ||
background-color: transparent; | ||
cursor: pointer; | ||
transition: opacity 0.3s ease-out; | ||
transition: background-color 0.3s ease-out; | ||
will-change: background-color; | ||
&:hover, | ||
&:active { | ||
opacity: 0.8; | ||
background-color: rgba(0, 0, 0, 0.08); | ||
} | ||
`; | ||
|
||
const TextButton = ({ handleClick, ...props }) => ( | ||
<StyledButton {...props} onClick={handleClick} /> | ||
const TextButton = ({ size, ...props }) => ( | ||
<StyledButton {...props} size={size} /> | ||
); | ||
|
||
TextButton.propTypes = { | ||
handleClick: func.isRequired, | ||
size: oneOf(['small', 'medium', 'large']), | ||
color: string, | ||
}; | ||
|
||
TextButton.defaultProps = { | ||
size: 'medium', | ||
color: BLACK, | ||
}; | ||
|
||
export default TextButton; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import { css } from 'styled-components'; | ||
|
||
const configs = { | ||
small: { | ||
height: 20, | ||
padding: 8, | ||
fontSize: 12, | ||
}, | ||
medium: { | ||
height: 32, | ||
padding: 21, | ||
fontSize: 14, | ||
}, | ||
large: { | ||
height: 42, | ||
padding: 25, | ||
fontSize: 16, | ||
}, | ||
}; | ||
|
||
export const sizes = size => { | ||
const { height, padding, fontSize } = configs[size] || configs.medium; | ||
|
||
return css` | ||
height: ${height}px; | ||
line-height: ${height}px; | ||
border-radius: ${height / 2}px; | ||
padding: 0 ${padding}px; | ||
font-size: ${fontSize}px; | ||
`; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import styled from 'styled-components'; | ||
import { LIGHT_BLACK } from '@/styles/colors'; | ||
|
||
const Empty = styled.div` | ||
color: ${LIGHT_BLACK}; | ||
`; | ||
|
||
export default Empty; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
import React from 'react'; | ||
import styled from 'styled-components'; | ||
import { bool, string, node } from 'prop-types'; | ||
import { BLACK, LIGHT_WHITE, GRAY } from '@/styles/colors'; | ||
import Loading from '@/components/Loading'; | ||
import ErrorMessage from '@/components/ErrorMessage'; | ||
|
||
export const TableRow = styled.tr` | ||
height: 56px; | ||
line-height: 56px; | ||
border: 1px solid ${GRAY}; | ||
border-top: 0; | ||
&:hover { | ||
background-color: rgba(0, 0, 0, 0.01); | ||
} | ||
`; | ||
|
||
export const TableData = styled.td` | ||
padding: 0 16px; | ||
text-align: ${props => props.align || 'left'}; | ||
`; | ||
|
||
const Error = styled(ErrorMessage)` | ||
position: absolute; | ||
left: 50%; | ||
top: 50%; | ||
transform: translate(-50%, -50%); | ||
`; | ||
|
||
export const TableContent = ({ isLoading, error, children }) => { | ||
if (isLoading) { | ||
return ( | ||
<TableRow> | ||
<Loading as="td" /> | ||
<TableData /> | ||
</TableRow> | ||
); | ||
} else if (error) { | ||
return ( | ||
<TableRow> | ||
<td> | ||
<Error>{error}</Error> | ||
</td> | ||
<TableData /> | ||
</TableRow> | ||
); | ||
} | ||
|
||
return children; | ||
}; | ||
|
||
TableContent.propTypes = { | ||
isLoading: bool.isRequired, | ||
error: string.isRequired, | ||
children: node.isRequired, | ||
}; | ||
|
||
export const TableHead = styled.th` | ||
padding: 0 16px; | ||
text-align: ${props => props.align || 'left'}; | ||
`; | ||
|
||
export const TableHeader = styled.thead` | ||
color: ${LIGHT_WHITE}; | ||
background-color: ${BLACK}; | ||
`; | ||
|
||
const Table = styled.table` | ||
position: relative; | ||
min-width: 768px; | ||
min-height: 300px; | ||
border-spacing: 0; | ||
border-collapse: collapse; | ||
`; | ||
|
||
export default Table; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import React from 'react'; | ||
import { string, number } from 'prop-types'; | ||
import isAdmin from '@/utils/isAdmin'; | ||
import TextButton from '@/components/Button/TextButton'; | ||
import Badge from '@/components/Badge'; | ||
import { TableRow, TableData } from '@/components/Table'; | ||
|
||
const Employee = ({ email, role }) => ( | ||
<TableRow> | ||
<TableData> | ||
<span>{email}</span> | ||
{isAdmin({ role }) && <Badge size="small">admin</Badge>} | ||
</TableData> | ||
<TableData align="right"> | ||
<TextButton>Edit</TextButton> | ||
</TableData> | ||
</TableRow> | ||
); | ||
|
||
Employee.propTypes = { | ||
email: string.isRequired, | ||
role: number.isRequired, | ||
}; | ||
|
||
export default Employee; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import React, { useEffect } from 'react'; | ||
import styled from 'styled-components'; | ||
import { useSelector, useDispatch } from 'react-redux'; | ||
import { | ||
selectUserList, | ||
selectIsLoading, | ||
selectError, | ||
getUserListThunk, | ||
} from '@/redux/slices/users'; | ||
import Table, { | ||
TableHeader, | ||
TableHead, | ||
TableRow, | ||
TableContent, | ||
} from '@/components/Table'; | ||
import Employee from './Employee'; | ||
|
||
const Container = styled.div` | ||
border-radius: 4px; | ||
overflow: hidden; | ||
`; | ||
|
||
const EmployeeList = () => { | ||
const userList = useSelector(selectUserList); | ||
const isLoading = useSelector(selectIsLoading); | ||
const error = useSelector(selectError); | ||
const dispatch = useDispatch(); | ||
|
||
useEffect(() => { | ||
dispatch(getUserListThunk()); | ||
}, [dispatch]); | ||
|
||
return ( | ||
<Container> | ||
<Table> | ||
<TableHeader> | ||
<TableRow> | ||
<TableHead align="left">Email</TableHead> | ||
<TableHead /> | ||
</TableRow> | ||
</TableHeader> | ||
<tbody> | ||
<TableContent isLoading={isLoading} error={error}> | ||
{userList.map(({ id, email, role }) => ( | ||
<Employee key={id} email={email} role={role} /> | ||
))} | ||
</TableContent> | ||
</tbody> | ||
</Table> | ||
</Container> | ||
); | ||
}; | ||
|
||
export default EmployeeList; |
Oops, something went wrong.