환율 계산기


프리온보딩 구현 과제

API를 통해 환율값을 받아 와, 실시간 환율 계산을 할 수 있도록 하는 계산기를 구현해봤다.

배포 주소

http://beefplz.s3-website.ap-northeast-2.amazonaws.com

사용 기술 및 스택

  • Stack
    • React Hooks
    • styled-components
    • fetch
    • Deploy : Netilfy
    • Other : Git / GitHub
    • Build Tool (Create React App)
    • Code Quality Tool (Prettier)

디렉토리 구조 (CRA Project Structure)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
src

├─components
│ │
│ └─SelectConverter
│ SelectBox.jsx
│ │ SelectConverter.jsx
│ └─TabConverter
│ FormBox.jsx
│ ResultBox.jsx
│ TabConverter.jsx

├─constants
│ index.js

├─pages
│ MainPage.jsx

├─styles
│ GlobalStyles.js

├─utils
│ dateConverter.js


표기법

케이스 약속
폴더명 소문자로 작성
파일명 파스칼케이스 (PascalCase)
변수명 카멜 케이스 (camelCase)
constants 대문자 + 언더바 조합 (BACKGROUND_COLOR)

레이아웃

MainPage.jsx의 기본 레이아웃은 화면에 가득 차도록 하여 그 안에 들어오는 두 계산기 컴포넌트들이 절반씩을 차지할 수 있도록 flex를 준다.

전체 레이아웃

그리고 각 계산기 컴포넌트의 컨테이너는 50vw만큼을 준 뒤, display: flex를 주고 모두 중앙 정렬 시킨다.

컴포넌트 레이아웃


탭 계산기 (박훈주, 이주영)

탭 계산기

  • 레이아웃 및 UI 설계 (input, select 로 입력값 설정 후 하단의 탭박스에 결과값 출력)
  • 선택된 통화의 종류에 따라 Tab의 구성이 유동적으로 변화되도록 구현
    ex) 드롭다운 메뉴를 “USD” → “CAD”로 바꿀 경우, 탭 내부의 “CAD”는 제거되고 “USD” 추가.
    
  • 선택된 Tab의 border-bottom만 제거되도록 구현
  • input 박스에 숫자만 입력되도록 설정 후 회계/통화 형식에 맞춰 콤마(,)가 천의 자리마다 찍힐 수 있도록 구현 ex) ‘2000’ 입력 시 ‘2,000’ 으로 출력
  • API를 통해 실시간으로 환율 데이터를 가져와서 환율 계산기 구현.
    환율 연산식 : `input 입력값 * (탭에서 선택된 통화 / 드롭다운에서 선택된 통화)`
    

컴포넌트 레이아웃

TabConverter의 컴포넌트 구성

1
2
3
4
5
// TabConverter.jsx
<TabConverterContainer>
<FormBox />
<ResultBox />
</TabConverterContainer>

기능 구현

  • 기준통화를 변경할 때마다 아래의 Tab 리스트가 변경되어야 한다.
  • 입력값이 1000 이상일 때는 셋째 자리수마다 콤마가 찍혀야 한다.
  • 선택된 기준통화에 따른 국가들의 환율 환산값이 계산되어야 한다.

1. 기준통화 변경될 때마다 Tab 리스트 변경하기

constants에 tab에 들어갈 고정된 국가별 통화들을 배열로 입력해뒀다.
그리고 기준통화가 변경될 때마다 filter()를 활용해 tab배열이 변화되도록 구현했다.

1
2
3
// ../constants/index.js

export const TAB_CURRENCY = ['USD', 'KRW', 'JPY', 'CAD', 'HKD', 'CNY'];
1
2
3
4
5
6
7
8
9
10
11
12
13
// ResultBox.jsx
useEffect(() => {
// useEffect를 통해 기준통화가 변경될 때마다 아래 함수가 실행되도록 했다.
const handleTab = () => {
// TAB_CURRENCT 상수를 불러와 filter한다. (기준통화와 같지 않은 값들만 필터링된다)
let changedTabs = TAB_CURRENCY.filter((tab) => tab !== currency);
// 그리고 Tabs에 기준통화가 제외된 새로운 배열이 담긴다
setTabs(changedTabs);
// 그리고 첫 번째 탭으로 지정되어야 할 국가가 currentTab에 저장된다.(첫 탭이 디폴트로 선택되도록 하기 위함)
setCurrentTab(changedTabs[0]);
};
handleTab();
}, [currency, setCurrentTab]);

2. 숫자에 콤마 표시, 그리고 소수점 자리수 제한

toLocaleString() 을 활용했으며, 원활하고 즉각적인 input value를 받아오기 위해 onChangeonKeyUp 이벤트를 같이 사용했다.

1
2
3
4
5
6
7
8
// onChange, onKeyUp 모두 사용
<input
type='text'
placeholder='값을 입력하세요'
value={inputValue}
onChange={(e) => handleType(e)}
onKeyUp={(e) => handleType(e)}
/>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const handleType = (e) => {
// 1000이 넘어갔을 때 콤마를 붙여줘야 하는데... 콤마가 붙으면 더이상 숫자가 아니다.
// 따라서 해당 값을 콤마를 제거한 상태로 초기화시켜줘야 한다.
const pureString = e.target.value.split(',').join('');
if (isNaN(Number(pureString))) {
return;
}
// 따라서 1000 이상의 값이 입력됐을 때 이전에 입력된 값이 콤마가 붙은 string이면 아래의 조건문에 걸리지 않는다.
// 이 때문에 pureString을 선언하여 사용한건 것이다.
if (Number(pureString) >= 1000) {
// 이 조건문에 해당된다면, 다시 콤마를 붙여줘야 한다. (toLocaleString을 활용했다)
setInputValue(
Number(pureString).toLocaleString('en', {
maximumFractionDigits: 3,
})
);
return;
}
// 1000보다 작으면 그냥 pureString을 넣어준다.
setInputValue(pureString);
};

toLocaleString() 사용법

1
2
3
let testNum = 1234;
// 한국식 회계 콤마 표준, 그리고 소수점은 둘 째 자리까지 허용
testNum.toLocaleString('ko-KR', { maximumFractionDigits: 2 });

3. 환율 계산

calculator()라는 함수를 만들어 계산했다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// ResultBox.jsx
// 기준통화가 base, 상대국 통화가 target이다.
const calculator = (target, base) => {
// api 데이터의 value값은 다 USD기준이기에 'USDOOO'으로 표기되어있다.
// 따라서 아래와 같이 앞에 USD를 붙여준 뒤 해당 값을 가져왔다.
let targetRate = apiData.quotes[`USD${target}`];
let baseRate = apiData.quotes[`USD${base}`];
// 미국 통화가 기준이기에 모든 환율값의 분모는 USD다. 따라서 그냥 나눗셈을 해주면 자동 약분처리되기 때문에 쉽게 계산할 수 있다.
// 계산식은 => (상대국 환율 / 기준국 환율) * input에 적은 액수
let exchangeRate = Number((targetRate / baseRate) * writtenMoney);
// 마지막으로 해당 환율값의 소숫점은 둘째 자리까지, 콤마 표기도 해줘야 하기 때문에 아래와 같이 리턴해준다.
return exchangeRate.toLocaleString('en', {
maximumFractionDigits: 2,
});
};

Author

Hoonjoo

Posted on

2022-01-27

Updated on

2022-02-07

Licensed under

Comments