-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(utils): Add formatNumberCurrency, formatNumberByUnits (#114)
* feat(react): useFileReader 추가 * feat(utils): formatNumberByUnits, formatNumberCurrency 추가 * chore: changeset * docs: formatNumberCurrency, formatNumberByUnits 문서 추가 * chore: @modern-kit/utils string isValidEmail export 제거 * fix: formatNumberByUnits 로직 수정 * fix: 불 필요한 테스트 유틸 파일 제거
- Loading branch information
Showing
16 changed files
with
467 additions
and
4 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,6 @@ | ||
--- | ||
'@modern-kit/utils': minor | ||
'@modern-kit/react': patch | ||
--- | ||
|
||
feat(utils): formatNumberByUnits, formatNumberCurrency 추가 |
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,73 @@ | ||
# formatNumberByUnits | ||
|
||
인자로 받은 숫자를 `단위 별로 구분`해주는 함수입니다. | ||
|
||
<br /> | ||
|
||
## Interface | ||
```tsx | ||
interface Unit { | ||
unit: string; | ||
value: number; | ||
} | ||
|
||
type FloorUnit = | ||
| 1 | ||
| 10 | ||
| 100 | ||
| 1000 | ||
| 10000 | ||
| 100000 | ||
| 1000000 | ||
| 10000000 | ||
| 100000000; | ||
|
||
interface FormatNumberByUnitsOption { | ||
units?: Unit[]; // default: [] | ||
withCommas?: boolean; // default: false, | ||
floorUnit?: FloorUnit; // default: 1, | ||
insertSpace?: boolean; // default: false, | ||
} | ||
|
||
const formatNumberByUnits: ( | ||
value: number, | ||
options?: FormatNumberByUnitsOption | ||
) => string; | ||
``` | ||
|
||
## Usage | ||
```ts | ||
import { formatNumberByUnits } from '@modern-kit/utils'; | ||
|
||
const ONE_HUNDRED_MILLION = 100000000; | ||
const TEN_THOUSAND = 10000; | ||
|
||
const units = [ | ||
{ unit: '억', value: ONE_HUNDRED_MILLION }, | ||
{ unit: '만', value: TEN_THOUSAND }, | ||
]; | ||
|
||
const value1 = formatNumberByUnits(450000000, { | ||
units: units, | ||
}); // '4억5000만' | ||
|
||
// withCommas옵션으로 천 단위마다 콤마를 추가할 수 있습니다. | ||
const value2 = formatNumberByUnits(450000000, { | ||
withCommas: true, | ||
units: units, | ||
}); // '4억5,000만' | ||
|
||
// insertSpace옵션으로 단위 마다 띄어쓰기를 추가할 수 있습니다. | ||
const value3 = formatNumberByUnits(450000000, { | ||
units: units, | ||
withCommas: true, | ||
insertSpace: true, | ||
}); // '4억 5,000만' | ||
|
||
// floorUnit 옵션으로 해당 단위 미만의 값들을 버릴 수 있습니다. | ||
const value4 = formatNumberByUnits(459325300, { | ||
units: units, | ||
withCommas: false, | ||
floorUnit: 10000000, | ||
}); // '4억5000만' | ||
``` |
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,106 @@ | ||
# formatNumberCurrency | ||
|
||
인자로 받은 숫자를 `단위 별로 구분`하고 `통화 단위`를 추가할 수 있습니다. | ||
|
||
<br /> | ||
|
||
## Interface | ||
```tsx | ||
interface CurrencyOption { | ||
currency: string; | ||
currencyPosition: 'prefix' | 'suffix'; | ||
} | ||
|
||
/* | ||
units?: Unit[]; // default: [] | ||
floorUnit?: FloorUnit; // default: 1, | ||
withCommas?: boolean; // default: false, | ||
insertSpace?: boolean; // default: false, | ||
currency?: string; // default: '' | ||
currencyPosition?: 'prefix' | 'suffix'; // default: 'suffix' | ||
*/ | ||
type FormatNumberCurrencyOptions = FormatNumberByUnitsOption & | ||
Partial<CurrencyOption>; | ||
|
||
const formatNumberCurrency: ( | ||
value: number, | ||
options?: FormatNumberCurrencyOptions | ||
) => string; | ||
``` | ||
|
||
## Usage | ||
### Basic | ||
기본적인 사용법은 아래와 같습니다. | ||
```ts | ||
import { formatNumberCurrency } from '@modern-kit/utils'; | ||
|
||
const ONE_HUNDRED_MILLION = 100000000; | ||
const TEN_THOUSAND = 10000; | ||
|
||
const units = [ | ||
{ unit: '억', value: ONE_HUNDRED_MILLION }, | ||
{ unit: '만', value: TEN_THOUSAND }, | ||
]; | ||
|
||
const value1 = formatNumberCurrency(450000000, { | ||
units: units, | ||
currency: '원', | ||
currencyPosition: 'suffix', | ||
}); // '4억5000만원' | ||
|
||
const value2 = formatNumberCurrency(4500, { | ||
currency: '$', | ||
currencyPosition: 'prefix', | ||
}); // '$4500' | ||
|
||
// withCommas 옵션으로 천 단위마다 콤마를 추가할 수 있습니다. | ||
const value2 = formatNumberCurrency(450000000, { | ||
units: units, | ||
withCommas: true, | ||
currency: '원', | ||
currencyPosition: 'suffix', | ||
}); // '4억5,000만원' | ||
|
||
// insertSpace 옵션으로 단위 마다 띄어쓰기를 추가할 수 있습니다. | ||
const value3 = formatNumberCurrency(450000000, { | ||
units: units, | ||
withCommas: true, | ||
currency: '원', | ||
currencyPosition: 'suffix', | ||
insertSpace: true, | ||
}); // '4억 5,000만원' | ||
|
||
// floorUnit 옵션으로 해당 단위 미만의 값들을 버릴 수 있습니다. | ||
const value4 = formatNumberCurrency(459325300, { | ||
units: units, | ||
currency: '원', | ||
currencyPosition: 'suffix', | ||
floorUnit: 10000000, | ||
}); // '4억5000만원' | ||
``` | ||
|
||
<br /> | ||
|
||
### ⭐️Abstraction | ||
아래와 같이 필요에 맞게 `추상화`해서 사용하는 것을 추천드립니다. | ||
|
||
```ts | ||
const ONE_HUNDRED_MILLION = 100000000; | ||
const TEN_THOUSAND = 10000; | ||
|
||
const units = [ | ||
{ unit: '억', value: ONE_HUNDRED_MILLION }, | ||
{ unit: '만', value: TEN_THOUSAND }, | ||
]; | ||
|
||
const formatToKRW = (value: number) => { | ||
return formatNumberCurrency(value, { | ||
units: units, | ||
currency: '원', | ||
currencyPosition: 'suffix', | ||
}); | ||
} | ||
|
||
const value1 = formatToKRW(42000000); // 4200만원 | ||
const value2 = formatToKRW(425000000); // 4억2500만원 | ||
``` |
File renamed without changes.
File renamed without changes.
74 changes: 74 additions & 0 deletions
74
packages/utils/src/formatter/formatNumberByUnits/formatNumberByUnits.spec.ts
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,74 @@ | ||
import { formatNumberByUnits } from '.'; | ||
|
||
const ONE_HUNDRED_MILLION = 100000000; | ||
const TEN_THOUSAND = 10000; | ||
|
||
const testUnits = [ | ||
{ unit: '억', value: ONE_HUNDRED_MILLION }, | ||
{ unit: '만', value: TEN_THOUSAND }, | ||
]; | ||
|
||
describe('formatNumberByUnits', () => { | ||
it('should format numbers based on the provided options', () => { | ||
const testValue1 = formatNumberByUnits(4500000, { | ||
withCommas: false, | ||
units: testUnits, | ||
}); | ||
expect(testValue1).toBe('450만'); | ||
|
||
const testValue2 = formatNumberByUnits(450000000, { | ||
withCommas: false, | ||
units: testUnits, | ||
}); | ||
expect(testValue2).toBe('4억5000만'); | ||
|
||
const testValue3 = formatNumberByUnits(459005300, { | ||
withCommas: false, | ||
units: testUnits, | ||
}); | ||
expect(testValue3).toBe('4억5900만5300'); | ||
|
||
const testValue4 = formatNumberByUnits(459005300, { | ||
withCommas: true, | ||
units: testUnits, | ||
}); | ||
expect(testValue4).toBe('4억5,900만5,300'); | ||
}); | ||
|
||
it('should add spaces between units when the insertSpace option is provided', () => { | ||
const testValue2 = formatNumberByUnits(450000000, { | ||
withCommas: true, | ||
units: testUnits, | ||
insertSpace: true, | ||
}); | ||
expect(testValue2).toBe('4억 5,000만'); | ||
}); | ||
|
||
it('should discard values below the specified floorUnit when provided', () => { | ||
const testValue1 = formatNumberByUnits(459325300, { | ||
floorUnit: 10000, | ||
withCommas: false, | ||
units: testUnits, | ||
}); | ||
expect(testValue1).toBe('4억5932만'); | ||
|
||
const testValue2 = formatNumberByUnits(459325300, { | ||
floorUnit: 10000000, | ||
withCommas: false, | ||
units: testUnits, | ||
}); | ||
expect(testValue2).toBe('4억5000만'); | ||
|
||
const testValue4 = formatNumberByUnits(4000000, { | ||
floorUnit: 100000000, | ||
withCommas: false, | ||
units: testUnits, | ||
}); | ||
expect(testValue4).toBe('0'); | ||
}); | ||
|
||
it('should format using default values if no options are provided', () => { | ||
const testValue1 = formatNumberByUnits(450000000); | ||
expect(testValue1).toBe('450000000'); | ||
}); | ||
}); |
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,72 @@ | ||
import { formatNumberWithCommas } from '../formatNumberWithCommas'; | ||
|
||
interface Unit { | ||
unit: string; | ||
value: number; | ||
} | ||
|
||
type FloorUnit = | ||
| 1 | ||
| 10 | ||
| 100 | ||
| 1000 | ||
| 10000 | ||
| 100000 | ||
| 1000000 | ||
| 10000000 | ||
| 100000000; | ||
|
||
export interface FormatNumberByUnitsOption { | ||
units?: Unit[]; | ||
withCommas?: boolean; | ||
floorUnit?: FloorUnit; | ||
insertSpace?: boolean; | ||
} | ||
|
||
const getNumberWithConditionalCommas = (value: number, withCommas: boolean) => { | ||
return withCommas ? formatNumberWithCommas(value) : String(value); | ||
}; | ||
|
||
export const formatNumberByUnits = ( | ||
value: number, | ||
options: FormatNumberByUnitsOption = {} | ||
) => { | ||
const { | ||
units = [], | ||
insertSpace = false, | ||
withCommas = false, | ||
floorUnit = 1, | ||
} = options; | ||
|
||
if (value < floorUnit) { | ||
return String(0); | ||
} | ||
|
||
if (units.length === 0) { | ||
return getNumberWithConditionalCommas(value, withCommas); | ||
} | ||
|
||
const sortedUnits = [...units].sort((a, b) => b.value - a.value); | ||
let result = ''; | ||
let remainder = Math.floor(value / floorUnit) * floorUnit; | ||
|
||
sortedUnits.forEach(({ unit, value: unitValue }) => { | ||
const quotient = Math.floor(remainder / unitValue); | ||
|
||
if (quotient > 0) { | ||
result += `${getNumberWithConditionalCommas( | ||
quotient, | ||
withCommas | ||
)}${unit}`; | ||
|
||
if (insertSpace) result += ' '; | ||
remainder %= unitValue; | ||
} | ||
}); | ||
|
||
if (remainder > 0) { | ||
result += `${getNumberWithConditionalCommas(remainder, withCommas)}`; | ||
} | ||
|
||
return result.trim(); | ||
}; |
Oops, something went wrong.