개발일기
[내일배움캠프] 최종 프로젝트 - Sweetalert를 이용해 alert/confirm창 만들기, 공통 Input 컴포넌트 생성 본문
카테고리 없음
[내일배움캠프] 최종 프로젝트 - Sweetalert를 이용해 alert/confirm창 만들기, 공통 Input 컴포넌트 생성
코찡 2023. 8. 20. 18:131. Sweetalert를 이용해 alert/confirm창 만들기
1) 패키지 설치
yarn add sweetalert2
2) index.html의 body 부분에 다음의 코드 심어주기
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/sweetalert2@11.4.10/dist/sweetalert2.min.css" />
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11.4.10/dist/sweetalert2.min.js"></script>
3) Alert 및 Confirm 함수 생성 (message 커스텀 가능하도록)
// components 폴더 하위 common 폴더 하위 modal 폴더 하위 alert.ts
import Swal from 'sweetalert2';
type AlertProps = {
title: string;
position?: 'top' | 'top-start' | 'top-end' | 'center' | 'center-start' | 'center-end' | 'bottom' | 'bottom-start' | 'bottom-end';
};
type AlertErrorProps = {
title?: string;
text?: string;
};
// 기본 alert창 -> position과 title 바꿔서 재사용 가능
export const Alert = ({ title, position = 'center' }: AlertProps) => {
Swal.fire({
position,
icon: 'success',
title,
showConfirmButton: false,
timer: 1000,
});
};
// alert창 (error) -> title과 text 바꿔서 재사용 가능
export const AlertError = ({ title = '에러가 발생했습니다.', text = '다시 시도해 주세요!' }: AlertErrorProps) => {
Swal.fire({
icon: 'error',
title,
text,
});
};
// 삭제 시 confirm 창 -> deleteMessage 입력 필수
export const ConfirmDelete = (deleteMessage: string) => {
Swal.fire({
title: '정말 삭제하시겠습니까?',
text: '이 작업은 되돌릴 수 없습니다.',
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: '네, 삭제하겠습니다.',
cancelButtonText: '취소',
}).then((result) => {
if (result.isConfirmed) {
Swal.fire('삭제됨', deleteMessage, 'success');
}
});
};
// 수정사항 저장 시 confirm 창
export const ConfirmSave = () => {
Swal.fire({
icon: 'question',
title: '수정사항을 반영하시겠습니까?',
showCancelButton: true,
confirmButtonText: '확인',
cancelButtonText: '취소',
}).then((result) => {
if (result.isConfirmed) {
Swal.fire('수정되었습니다!', '', 'success');
}
});
};
4) Alert 및 Confirm 함수 사용 예시
import { Alert, AlertError, ConfirmDelete, ConfirmSave } from '../components/common/modal/alert';
const Intro = () => {
// title 입력 필수, position은 입력하지 않으면 default 값 = center
const handleAlert = () => {
Alert({ title: '로그인 성공', position: 'top-end' });
};
// 빈 배열 넣으면 기본 error 메시지로 alert
// 다음과 같이 error 메시지 커스텀 가능 -> AlertError({ title: '에러다.', text: '이제 나가줘' });
const handleAlertError = () => {
AlertError({});
};
// 삭제 메시지 입력 필수
const handleConfirmDelete = () => {
ConfirmDelete('해당 댓글이 삭제되었습니다.');
};
const handleConfirmSave = () => {
ConfirmSave();
};
return (
<div>
<button onClick={handleAlert}>Alert 버튼</button>
<button onClick={handleAlertError}>AlertError 버튼</button>
<button onClick={handleConfirmDelete}>ConfirmDelete 버튼</button>
<button onClick={handleConfirmSave}>ConfirmSave 버튼</button>
</div>
);
};
export default Intro;
2. 공통 Input 컴포넌트 생성
1) Input.tsx -> InputProps 타입 지정 및 Textarea와 Input 구분
// components 폴더 하위 common 폴더 하위 input 폴더 하위 Input.tsx
import * as St from './style';
export interface InputProps {
id?: string;
name?: string;
type: 'text' | 'textarea' | 'email' | 'password';
inputStyleType: 'comment' | 'auth' | 'search' | 'write' | 'apply';
placeholder?: string;
value?: string;
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
border: boolean;
disabled?: boolean;
autoFocus?: boolean;
forwardRef?: React.MutableRefObject<HTMLInputElement | HTMLTextAreaElement | null>;
autocomplete?: string;
}
export const Input = ({ id, name, type, inputStyleType, placeholder, value, onChange, border, disabled, autoFocus, forwardRef, autocomplete }: InputProps) => {
if (type === 'textarea') {
return (
<St.Textarea
id={id}
name={name}
inputStyleType={inputStyleType}
placeholder={placeholder ?? ''}
value={value}
onChange={onChange}
border={border}
disabled={disabled}
autoFocus={autoFocus}
ref={forwardRef as React.MutableRefObject<HTMLTextAreaElement | null>}
autoComplete={autocomplete ?? 'off'}
/>
);
} else {
return (
<St.Input
id={id}
name={name}
type={type}
inputStyleType={inputStyleType}
placeholder={placeholder ?? ''}
value={value}
onChange={onChange}
border={border}
disabled={disabled}
autoFocus={autoFocus}
ref={forwardRef as React.MutableRefObject<HTMLInputElement | null>}
autoComplete={autocomplete ?? 'off'}
/>
);
}
};
2) Input의 css 관리하는 styled-components 코드
// components 폴더 하위 common 폴더 하위 input 폴더 하위 style.ts
import styled, { css } from 'styled-components';
import { InputProps } from './Input';
// Textarea는 type 값을 갖지 않으므로 InputProps 타입에서 빼고 적용
type TextareaProps = Omit<InputProps, 'type'>;
interface BaseStylesProps {
inputStyleType: 'comment' | 'auth' | 'search' | 'write' | 'apply';
border: boolean;
}
const baseStyles = css<BaseStylesProps>`
outline: none;
${(props) => {
switch (props.inputStyleType) {
case 'comment':
return css`
width: 60vw;
height: 15px;
padding: 7px 13px;
border-radius: 20px;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
`;
case 'auth':
return css`
width: 350px;
height: 15px;
padding: 7px 10px;
`;
case 'search':
return css`
width: 150px;
height: 20px;
padding: 4px;
border-radius: 20px;
text-align: center;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
`;
case 'write':
return css`
width: 40vw;
height: 13px;
padding: 7px 13px;
border-radius: 20px;
`;
case 'apply':
return css`
width: 40vw;
height: 20vw;
padding: 10px;
&::-webkit-scrollbar {
display: none;
}
`;
}
}}
${(props) =>
props.border
? css`
border: 1px solid gray;
`
: css`
border: none;
border-bottom: 1px solid gray;
`}
`;
export const Input = styled.input.attrs<InputProps>((props) => ({
type: props.type,
}))`
${baseStyles}
`;
export const Textarea = styled.textarea<TextareaProps>`
${baseStyles}
`;
3) 공통 Input 사용 예시
import { Input } from '../components/common/input';
const Intro = () => {
return (
<div>
<Input type="text" inputStyleType="comment" placeholder="댓글을 입력해주세요." border={true} />
<br />
<br />
<Input type="email" inputStyleType="auth" placeholder="이메일을 입력해주세요." border={false} />
<br />
<Input type="text" inputStyleType="auth" placeholder="닉네임을 입력해주세요." border={false} />
<br />
<Input type="password" inputStyleType="auth" placeholder="비밀번호를 입력해주세요." border={false} />
<br />
<br />
<Input type="text" inputStyleType="search" placeholder="검색어를 입력해주세요." border={true} />
<br />
<br />
<Input type="text" inputStyleType="write" placeholder="원활한 동료찾기를 위해 지역명을 함께 입력해주세요." border={true} />
<br />
<br />
<Input type="textarea" inputStyleType="apply" placeholder="간단한 자기소개를 입력해주세요." border={true} />
</div>
);
};
export default Intro;