diff --git a/jest.config.js b/jest.config.js index 114ccf38..e8f08cfc 100644 --- a/jest.config.js +++ b/jest.config.js @@ -6,7 +6,7 @@ const createJestConfig = nextJest({ const customJestConfig = { coverageProvider: 'v8', - testEnvironment: 'jsdom', + testEnvironment: 'jest-fixed-jsdom', setupFilesAfterEnv: ['/jest.setup.js'], moduleNameMapper: { '^@/(.*)$': '/src/$1', diff --git a/package.json b/package.json index d948566d..a162a7f2 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "axios": "^1.13.2", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "jest-fixed-jsdom": "^0.0.11", "motion": "^12.23.24", "next": "16.0.7", "react": "19.2.1", @@ -89,7 +90,7 @@ "jest": "^30.2.0", "jest-environment-jsdom": "^30.2.0", "lint-staged": "^16.2.4", - "msw": "^2.11.5", + "msw": "^2.11.2", "orval": "^7.13.2", "prettier": "^3.6.2", "prettier-plugin-tailwindcss": "^0.7.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 901a35e3..af9ec79f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -29,6 +29,9 @@ importers: clsx: specifier: ^2.1.1 version: 2.1.1 + jest-fixed-jsdom: + specifier: ^0.0.11 + version: 0.0.11(jest-environment-jsdom@30.2.0) motion: specifier: ^12.23.24 version: 12.23.24(@emotion/is-prop-valid@1.4.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1) @@ -71,7 +74,7 @@ importers: version: 10.0.5(@types/react@19.2.2)(esbuild@0.27.1)(storybook@10.1.4(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(webpack@5.102.1(esbuild@0.27.1)) '@storybook/nextjs': specifier: ^10.1.4 - version: 10.1.4(@types/webpack@5.28.5(esbuild@0.27.1))(babel-plugin-macros@3.1.0)(esbuild@0.27.1)(msw@2.11.5(@types/node@20.19.21)(typescript@5.9.3))(next@16.0.7(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(storybook@10.1.4(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(type-fest@4.41.0)(typescript@5.9.3)(webpack-hot-middleware@2.26.1)(webpack@5.102.1(esbuild@0.27.1)) + version: 10.1.4(@types/webpack@5.28.5(esbuild@0.27.1))(babel-plugin-macros@3.1.0)(esbuild@0.27.1)(msw@2.11.2(@types/node@20.19.21)(typescript@5.9.3))(next@16.0.7(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(storybook@10.1.4(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(type-fest@4.41.0)(typescript@5.9.3)(webpack-hot-middleware@2.26.1)(webpack@5.102.1(esbuild@0.27.1)) '@svgr/webpack': specifier: ^8.1.0 version: 8.1.0(typescript@5.9.3) @@ -151,8 +154,8 @@ importers: specifier: ^16.2.4 version: 16.2.4 msw: - specifier: ^2.11.5 - version: 2.11.5(@types/node@20.19.21)(typescript@5.9.3) + specifier: ^2.11.2 + version: 2.11.2(@types/node@20.19.21)(typescript@5.9.3) orval: specifier: ^7.13.2 version: 7.13.2(openapi-types@12.1.3)(typescript@5.9.3) @@ -959,6 +962,12 @@ packages: '@bcoe/v8-coverage@0.2.3': resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + '@bundled-es-modules/cookie@2.0.1': + resolution: {integrity: sha512-8o+5fRPLNbjbdGRRmJj3h6Hh1AQJf2dk3qQ/5ZFb+PXkRNiSoMGGUKlsgLfrxneb72axVJyIYji64E2+nNfYyw==} + + '@bundled-es-modules/statuses@1.0.1': + resolution: {integrity: sha512-yn7BklA5acgcBr+7w064fGV+SGIFySjCKpqjcWgBAIfrAkY+4GQTJJHQMeT3V/sgz23VTEVV8TtOmkvJAhFVfg==} + '@colors/colors@1.6.0': resolution: {integrity: sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==} engines: {node: '>=0.1.90'} @@ -2500,6 +2509,9 @@ packages: '@types/conventional-commits-parser@5.0.2': resolution: {integrity: sha512-BgT2szDXnVypgpNxOK8aL5SGjUdaQbC++WZNjF1Qge3Og2+zhHj+RWhmehLhYyvQwqAmvezruVfOf8+3m74W+g==} + '@types/cookie@0.6.0': + resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} + '@types/deep-eql@4.0.2': resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} @@ -3427,9 +3439,9 @@ packages: convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - cookie@1.0.2: - resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==} - engines: {node: '>=18'} + cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} + engines: {node: '>= 0.6'} core-js-compat@3.46.0: resolution: {integrity: sha512-p9hObIIEENxSV8xIu+V68JjSeARg6UVMG5mR+JEUguG3sI6MsiS1njz2jHmyJDvA+8jX/sytkBHup6kxhM9law==} @@ -4727,6 +4739,12 @@ packages: resolution: {integrity: sha512-ElU8v92QJ9UrYsKrxDIKCxu6PfNj4Hdcktcn0JX12zqNdqWHB0N+hwOnnBBXvjLd2vApZtuLUGs1QSY+MsXoNA==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + jest-fixed-jsdom@0.0.11: + resolution: {integrity: sha512-3UkjgM79APnmLVDnelrxdwz4oybD5qw6NLyayl7iCX8C8tJHeqjL9fmNrRlIrNiVJSXkF5t9ZPJ+xlM0kSwwYg==} + engines: {node: '>=18.0.0'} + peerDependencies: + jest-environment-jsdom: '>=28.0.0' + jest-haste-map@30.2.0: resolution: {integrity: sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} @@ -5249,8 +5267,8 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - msw@2.11.5: - resolution: {integrity: sha512-atFI4GjKSJComxcigz273honh8h4j5zzpk5kwG4tGm0TPcYne6bqmVrufeRll6auBeouIkXqZYXxVbWSWxM3RA==} + msw@2.11.2: + resolution: {integrity: sha512-MI54hLCsrMwiflkcqlgYYNJJddY5/+S0SnONvhv1owOplvqohKSQyGejpNdUGyCwgs4IH7PqaNbPw/sKOEze9Q==} engines: {node: '>=18'} hasBin: true peerDependencies: @@ -6672,9 +6690,6 @@ packages: unrs-resolver@1.11.1: resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} - until-async@3.0.2: - resolution: {integrity: sha512-IiSk4HlzAMqTUseHHe3VhIGyuFmN90zMTpD3Z3y8jeQbzLIq500MVM7Jq2vUAnTKAFPJrqwkzr6PoTcPhGcOiw==} - update-browserslist-db@1.1.3: resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} hasBin: true @@ -8512,6 +8527,14 @@ snapshots: '@bcoe/v8-coverage@0.2.3': {} + '@bundled-es-modules/cookie@2.0.1': + dependencies: + cookie: 0.7.2 + + '@bundled-es-modules/statuses@1.0.1': + dependencies: + statuses: 2.0.2 + '@colors/colors@1.6.0': {} '@commander-js/extra-typings@14.0.0(commander@14.0.1)': @@ -9780,10 +9803,10 @@ snapshots: - vite - webpack - '@storybook/builder-webpack5@10.1.4(esbuild@0.27.1)(msw@2.11.5(@types/node@20.19.21)(typescript@5.9.3))(storybook@10.1.4(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(typescript@5.9.3)': + '@storybook/builder-webpack5@10.1.4(esbuild@0.27.1)(msw@2.11.2(@types/node@20.19.21)(typescript@5.9.3))(storybook@10.1.4(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(typescript@5.9.3)': dependencies: '@storybook/core-webpack': 10.1.4(storybook@10.1.4(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)) - '@vitest/mocker': 3.2.4(msw@2.11.5(@types/node@20.19.21)(typescript@5.9.3)) + '@vitest/mocker': 3.2.4(msw@2.11.2(@types/node@20.19.21)(typescript@5.9.3)) case-sensitive-paths-webpack-plugin: 2.4.0 cjs-module-lexer: 1.4.3 css-loader: 7.1.2(webpack@5.103.0(esbuild@0.27.1)) @@ -9835,7 +9858,7 @@ snapshots: react: 19.2.1 react-dom: 19.2.1(react@19.2.1) - '@storybook/nextjs@10.1.4(@types/webpack@5.28.5(esbuild@0.27.1))(babel-plugin-macros@3.1.0)(esbuild@0.27.1)(msw@2.11.5(@types/node@20.19.21)(typescript@5.9.3))(next@16.0.7(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(storybook@10.1.4(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(type-fest@4.41.0)(typescript@5.9.3)(webpack-hot-middleware@2.26.1)(webpack@5.102.1(esbuild@0.27.1))': + '@storybook/nextjs@10.1.4(@types/webpack@5.28.5(esbuild@0.27.1))(babel-plugin-macros@3.1.0)(esbuild@0.27.1)(msw@2.11.2(@types/node@20.19.21)(typescript@5.9.3))(next@16.0.7(@babel/core@7.28.4)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(storybook@10.1.4(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(type-fest@4.41.0)(typescript@5.9.3)(webpack-hot-middleware@2.26.1)(webpack@5.102.1(esbuild@0.27.1))': dependencies: '@babel/core': 7.28.5 '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.28.5) @@ -9851,7 +9874,7 @@ snapshots: '@babel/preset-typescript': 7.28.5(@babel/core@7.28.5) '@babel/runtime': 7.28.4 '@pmmmwh/react-refresh-webpack-plugin': 0.5.17(@types/webpack@5.28.5(esbuild@0.27.1))(react-refresh@0.14.2)(type-fest@4.41.0)(webpack-hot-middleware@2.26.1)(webpack@5.102.1(esbuild@0.27.1)) - '@storybook/builder-webpack5': 10.1.4(esbuild@0.27.1)(msw@2.11.5(@types/node@20.19.21)(typescript@5.9.3))(storybook@10.1.4(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(typescript@5.9.3) + '@storybook/builder-webpack5': 10.1.4(esbuild@0.27.1)(msw@2.11.2(@types/node@20.19.21)(typescript@5.9.3))(storybook@10.1.4(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(typescript@5.9.3) '@storybook/preset-react-webpack': 10.1.4(esbuild@0.27.1)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(storybook@10.1.4(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(typescript@5.9.3) '@storybook/react': 10.1.4(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(storybook@10.1.4(@testing-library/dom@10.4.1)(prettier@3.6.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1))(typescript@5.9.3) '@types/semver': 7.7.1 @@ -10248,6 +10271,8 @@ snapshots: dependencies: '@types/node': 20.19.21 + '@types/cookie@0.6.0': {} + '@types/deep-eql@4.0.2': {} '@types/doctrine@0.0.9': {} @@ -10511,13 +10536,13 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/mocker@3.2.4(msw@2.11.5(@types/node@20.19.21)(typescript@5.9.3))': + '@vitest/mocker@3.2.4(msw@2.11.2(@types/node@20.19.21)(typescript@5.9.3))': dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - msw: 2.11.5(@types/node@20.19.21)(typescript@5.9.3) + msw: 2.11.2(@types/node@20.19.21)(typescript@5.9.3) '@vitest/pretty-format@3.2.4': dependencies: @@ -11261,7 +11286,7 @@ snapshots: convert-source-map@2.0.0: {} - cookie@1.0.2: {} + cookie@0.7.2: {} core-js-compat@3.46.0: dependencies: @@ -12895,6 +12920,10 @@ snapshots: jest-util: 30.2.0 jest-validate: 30.2.0 + jest-fixed-jsdom@0.0.11(jest-environment-jsdom@30.2.0): + dependencies: + jest-environment-jsdom: 30.2.0 + jest-haste-map@30.2.0: dependencies: '@jest/types': 30.2.0 @@ -13497,13 +13526,16 @@ snapshots: ms@2.1.3: {} - msw@2.11.5(@types/node@20.19.21)(typescript@5.9.3): + msw@2.11.2(@types/node@20.19.21)(typescript@5.9.3): dependencies: + '@bundled-es-modules/cookie': 2.0.1 + '@bundled-es-modules/statuses': 1.0.1 '@inquirer/confirm': 5.1.19(@types/node@20.19.21) '@mswjs/interceptors': 0.39.8 '@open-draft/deferred-promise': 2.2.0 + '@open-draft/until': 2.1.0 + '@types/cookie': 0.6.0 '@types/statuses': 2.0.6 - cookie: 1.0.2 graphql: 16.11.0 headers-polyfill: 4.0.3 is-node-process: 1.2.0 @@ -13511,11 +13543,9 @@ snapshots: path-to-regexp: 6.3.0 picocolors: 1.1.1 rettime: 0.7.0 - statuses: 2.0.2 strict-event-emitter: 0.5.1 tough-cookie: 6.0.0 type-fest: 4.41.0 - until-async: 3.0.2 yargs: 17.7.2 optionalDependencies: typescript: 5.9.3 @@ -15060,8 +15090,6 @@ snapshots: '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1 '@unrs/resolver-binding-win32-x64-msvc': 1.11.1 - until-async@3.0.2: {} - update-browserslist-db@1.1.3(browserslist@4.26.3): dependencies: browserslist: 4.26.3 diff --git a/src/app/(user)/profile/[userId]/page.test.tsx b/src/app/(user)/profile/[userId]/page.test.tsx new file mode 100644 index 00000000..50c2796c --- /dev/null +++ b/src/app/(user)/profile/[userId]/page.test.tsx @@ -0,0 +1,108 @@ +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { act, render, screen } from '@testing-library/react'; +import { http, HttpResponse } from 'msw'; + +import { formatISO } from '@/lib/formatDateTime'; +import { server } from '@/mock/server'; +import { createMockSuccessResponse } from '@/mock/service/common/common-mock'; +import { mockUserItems } from '@/mock/service/user/users-mock'; + +import ProfilePage from './page'; + +const createTestQueryClient = () => + new QueryClient({ + defaultOptions: { + queries: { + retry: false, // 테스트에서 재시도 비활성화 + gcTime: Infinity, // Jest 환경에서 카비지 컬렉션을 위한 타이머 생성 방지 + }, + }, + }); + +const renderWithQueryClient = async (component: React.ReactElement) => { + // 각 테스트마다 새로운 QueryClient 생성하여 독립적인 상태 유지 (useState 없이) + const testQueryClient = createTestQueryClient(); + let renderResult; + await act(async () => { + renderResult = render( + {component}, + ); + }); + + return renderResult; +}; + +describe('프로필 페이지 테스트', () => { + beforeAll(() => { + server.listen(); + }); + afterEach(() => { + server.resetHandlers(); + }); + afterAll(() => server.close()); + + test('프로필 정보가 올바르게 표시되는지 테스트', async () => { + const id = 2; + const user = mockUserItems.find((item) => item.userId === id)!; + + await renderWithQueryClient(); + + await screen.findByRole('img', { name: '프로필 이미지' }); + + expect(screen.getByRole('heading', { level: 1 })).toHaveTextContent(user.nickName); + expect(screen.getByText(user.profileMessage)).toBeInTheDocument(); + + expect(screen.getByText('팔로워')).toBeInTheDocument(); + expect(screen.getByText(user.followersCnt.toLocaleString())).toBeInTheDocument(); + expect(screen.getByText('팔로잉')).toBeInTheDocument(); + expect(screen.getByText(user.followeesCnt.toLocaleString())).toBeInTheDocument(); + + expect(screen.getByText('MBTI')).toBeInTheDocument(); + expect(screen.getByText(user.mbti)).toBeInTheDocument(); + expect(screen.getByText('가입 일자')).toBeInTheDocument(); + expect(screen.getByText(formatISO(user.createdAt))).toBeInTheDocument(); + expect(screen.getByText('모임 참여')).toBeInTheDocument(); + expect(screen.getByText(`${user.groupJoinedCnt}회`)); + expect(screen.getByText('모임 생성')).toBeInTheDocument(); + expect(screen.getByText(`${user.groupCreatedCnt}회`)); + }); + + test('팔로우 중이 아니면 팔로우 하기 버튼이 보이는지 테스트', async () => { + server.use( + http.get('*/users/2', () => { + return HttpResponse.json( + createMockSuccessResponse({ + ...mockUserItems[1], + isFollowing: false, + }), + ); + }), + ); + + await renderWithQueryClient(); + + await screen.findByRole('img', { name: '프로필 이미지' }); + + expect(screen.getByRole('button', { name: '팔로우 하기' })).toBeInTheDocument(); + expect(screen.queryByRole('button', { name: '팔로우 취소' })).not.toBeInTheDocument(); + }); + + test('팔로우 중이면 팔로우 취소 버튼이 보이는지 테스트', async () => { + server.use( + http.get('*/users/2', () => { + return HttpResponse.json( + createMockSuccessResponse({ + ...mockUserItems[1], + isFollowing: true, + }), + ); + }), + ); + await renderWithQueryClient(); + + await screen.findByRole('img', { name: '프로필 이미지' }); + + expect(screen.getByRole('button', { name: '팔로우 취소' })).toBeInTheDocument(); + expect(screen.queryByRole('button', { name: '팔로우 하기' })).not.toBeInTheDocument(); + }); +}); diff --git a/src/components/pages/notification/notification-card/index.tsx b/src/components/pages/notification/notification-card/index.tsx index 8cbfb029..4f26bcd8 100644 --- a/src/components/pages/notification/notification-card/index.tsx +++ b/src/components/pages/notification/notification-card/index.tsx @@ -1,7 +1,7 @@ import Link from 'next/link'; import { Icon } from '@/components/icon'; -import { formatTimeAgo } from '@/lib/format-time-ago'; +import { formatTimeAgo } from '@/lib/formatDateTime'; import { Notification, NotificationType } from '@/types/service/notification'; interface Props { diff --git a/src/components/pages/user/profile/profile-card/index.tsx b/src/components/pages/user/profile/profile-card/index.tsx index 55a2c669..65c70b70 100644 --- a/src/components/pages/user/profile/profile-card/index.tsx +++ b/src/components/pages/user/profile/profile-card/index.tsx @@ -11,9 +11,9 @@ export const ProfileCard = ({ user }: Props) => { return (
- image + 프로필 이미지
-

{nickName}

+

{nickName}

{profileMessage}

); diff --git a/src/components/pages/user/profile/profile-follows-badge/index.tsx b/src/components/pages/user/profile/profile-follows-badge/index.tsx index bf1c384a..c18cf004 100644 --- a/src/components/pages/user/profile/profile-follows-badge/index.tsx +++ b/src/components/pages/user/profile/profile-follows-badge/index.tsx @@ -10,11 +10,11 @@ export const ProfileFollowsBadge = ({ user }: Props) => { const listMap = [ { label: '팔로워', - value: user.followersCnt, + value: user.followersCnt.toLocaleString(), }, { label: '팔로잉', - value: user.followeesCnt, + value: user.followeesCnt.toLocaleString(), }, ]; @@ -25,8 +25,8 @@ export const ProfileFollowsBadge = ({ user }: Props) => { {listMap.map((item, index) => (
- {item.value.toLocaleString()} - {item.label.toLocaleString()} + {item.value} + {item.label}
{index < listLength - 1 &&
} diff --git a/src/lib/format-time-ago.ts b/src/lib/formatDateTime.ts similarity index 76% rename from src/lib/format-time-ago.ts rename to src/lib/formatDateTime.ts index 0ad60a06..82ffe8a1 100644 --- a/src/lib/format-time-ago.ts +++ b/src/lib/formatDateTime.ts @@ -1,3 +1,11 @@ +export const formatISO = (dateString: string) => { + const date = new Date(dateString); + const y = date.getFullYear(); + const m = String(date.getMonth() + 1).padStart(2, '0'); + const d = String(date.getDate()).padStart(2, '0'); + return `${y}. ${m}. ${d}`; +}; + export const formatTimeAgo = (isoString: string) => { const dateInput = new Date(isoString); const dateNow = new Date();