toast 메시지 추가
alert 글로벌화 loading 글로벌화
This commit is contained in:
156
src/components/common/alert/ToastAlert.js
Normal file
156
src/components/common/alert/ToastAlert.js
Normal file
@@ -0,0 +1,156 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import styled, { keyframes, css, createGlobalStyle } from 'styled-components';
|
||||
import { alertTypes } from '../../../assets/data/types';
|
||||
|
||||
const ToastAlert = ({ id, message, type = alertTypes.info, position = 'top-center', onClose }) => {
|
||||
const [isVisible, setIsVisible] = useState(false);
|
||||
|
||||
const handleClose = () => {
|
||||
setIsVisible(true);
|
||||
setTimeout(() => {
|
||||
onClose();
|
||||
}, 300);
|
||||
};
|
||||
|
||||
return (
|
||||
<ToastContainer $type={type} $position={position} $isVisible={isVisible}>
|
||||
<IconWrapper $type={type}>
|
||||
<ToastIcon type={type} />
|
||||
</IconWrapper>
|
||||
<ToastMessage>{message}</ToastMessage>
|
||||
<CloseButton onClick={handleClose}>×</CloseButton>
|
||||
</ToastContainer>
|
||||
);
|
||||
};
|
||||
|
||||
const ToastIcon = ({ type }) => {
|
||||
switch (type) {
|
||||
case alertTypes.success:
|
||||
return <span>✓</span>;
|
||||
case alertTypes.error:
|
||||
return <span>✗</span>;
|
||||
case alertTypes.warning:
|
||||
return <span>⚠</span>;
|
||||
case alertTypes.info:
|
||||
default:
|
||||
return <span>ℹ</span>;
|
||||
}
|
||||
};
|
||||
|
||||
const fadeIn = keyframes`
|
||||
from { opacity: 0; transform: translateX(-50%) translateY(-20px); }
|
||||
to { opacity: 1; transform: translateX(-50%) translateY(0); }
|
||||
`;
|
||||
|
||||
const fadeOut = keyframes`
|
||||
from { opacity: 1; transform: translateX(-50%) translateY(0); }
|
||||
to { opacity: 0; transform: translateX(-50%) translateY(-20px); }
|
||||
`;
|
||||
|
||||
// 위치에 따른 스타일 지정 함수
|
||||
const getPositionStyle = (position) => {
|
||||
const positions = {
|
||||
'top-left': css`
|
||||
top: 20px;
|
||||
left: 20px;
|
||||
`,
|
||||
'top-center': css`
|
||||
top: 20px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%) translateY(0);
|
||||
`,
|
||||
'top-right': css`
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
`,
|
||||
'bottom-left': css`
|
||||
bottom: 20px;
|
||||
left: 20px;
|
||||
`,
|
||||
'bottom-center': css`
|
||||
bottom: 20px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%) translateY(0);
|
||||
`,
|
||||
'bottom-right': css`
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
`
|
||||
};
|
||||
|
||||
return positions[position] || positions['top-center'];
|
||||
};
|
||||
|
||||
// 타입에 따른 스타일 지정 함수
|
||||
const getTypeStyle = (type) => {
|
||||
const types = {
|
||||
[alertTypes.success]: css`
|
||||
background-color: #d4edda;
|
||||
color: #155724;
|
||||
border-color: #c3e6cb;
|
||||
`,
|
||||
[alertTypes.error]: css`
|
||||
background-color: #f8d7da;
|
||||
color: #721c24;
|
||||
border-color: #f5c6cb;
|
||||
`,
|
||||
[alertTypes.warning]: css`
|
||||
background-color: #fff3cd;
|
||||
color: #856404;
|
||||
border-color: #ffeeba;
|
||||
`,
|
||||
[alertTypes.info]: css`
|
||||
background-color: #d1ecf1;
|
||||
color: #0c5460;
|
||||
border-color: #bee5eb;
|
||||
`
|
||||
};
|
||||
|
||||
return types[type] || types['info'];
|
||||
};
|
||||
|
||||
const ToastContainer = styled.div`
|
||||
position: fixed;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-width: 250px;
|
||||
max-width: 450px;
|
||||
padding: 12px 15px;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
margin-bottom: 10px;
|
||||
z-index: 9999;
|
||||
|
||||
animation: ${props => props.$isExiting ? fadeOut : fadeIn} 0.3s ease forwards;
|
||||
|
||||
${props => getPositionStyle(props.$position)}
|
||||
${props => getTypeStyle(props.$type)}
|
||||
`;
|
||||
|
||||
const IconWrapper = styled.div`
|
||||
margin-right: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 18px;
|
||||
`;
|
||||
|
||||
const ToastMessage = styled.div`
|
||||
flex: 1;
|
||||
padding-right: 10px;
|
||||
`;
|
||||
|
||||
const CloseButton = styled.button`
|
||||
background: transparent;
|
||||
border: none;
|
||||
font-size: 18px;
|
||||
cursor: pointer;
|
||||
color: inherit;
|
||||
opacity: 0.7;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
`;
|
||||
|
||||
export default ToastAlert;
|
||||
Reference in New Issue
Block a user