Skip to content

Commit

Permalink
feat(utils): Add formatNumberCurrency, formatNumberByUnits (#114)
Browse files Browse the repository at this point in the history
* 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
ssi02014 authored May 11, 2024
1 parent ef5707f commit bf9bcc2
Show file tree
Hide file tree
Showing 16 changed files with 467 additions and 4 deletions.
6 changes: 6 additions & 0 deletions .changeset/sour-rice-stare.md
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 추가
73 changes: 73 additions & 0 deletions docs/docs/utils/formatter/formatNumberByUnits.md
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만'
```
106 changes: 106 additions & 0 deletions docs/docs/utils/formatter/formatNumberCurrency.md
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.
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');
});
});
72 changes: 72 additions & 0 deletions packages/utils/src/formatter/formatNumberByUnits/index.ts
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();
};
Loading

0 comments on commit bf9bcc2

Please sign in to comment.