Skip to content
Merged
12 changes: 12 additions & 0 deletions src/api/home/dateCourse.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type { IDateCourseSavedCountResponse } from '../../types/home/dateCourse';
import { axiosInstance } from '../axiosInstance';

// 데이트 코스 저장 횟수 조회 API
export const getDateCourseSavedCount = async (): Promise<IDateCourseSavedCountResponse> => {
try {
const response = await axiosInstance.get('/api/v1/logs/datecourses/saved-count');
return response.data;
} catch {
throw new Error('데이트 코스 저장 횟수를 가져오는데 실패했습니다.');
}
};
7 changes: 7 additions & 0 deletions src/api/home/datePlace.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { TMonthlyDatePlaceResponse } from '../../types/home/datePlace';
import { axiosInstance } from '../axiosInstance';

export const getMonthlyDatePlaceStates = async (): Promise<TMonthlyDatePlaceResponse> => {
const { data } = await axiosInstance.get('/api/v1/logs/dateplaces/monthly');
return data;
};
17 changes: 17 additions & 0 deletions src/api/home/dateTimes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type { TGetDateTimeStats, TMonthlyDatePlaceResponse } from '../../types/home/datePlace';
import { axiosInstance } from '../axiosInstance';

// 월별 데이트 장소 수 조회 API
export const getMonthlyDatePlaceStats = async (): Promise<TMonthlyDatePlaceResponse> => {
try {
const response = await axiosInstance.get('/api/v1/logs/dateplaces/monthly');
return response.data;
} catch {
throw new Error('월별 데이트 장소 통계를 가져오는데 실패했습니다.');
}
};

export const getDateTimeStats = async (): Promise<TGetDateTimeStats> => {
const { data } = await axiosInstance.get('/api/v1/logs/datecourses/average');
return data;
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

에러 처리가 누락되었습니다.

위의 getMonthlyDatePlaceStats 함수와 달리 이 함수에는 에러 처리가 없습니다. 일관성을 위해 try-catch 블록을 추가하시기 바랍니다.

🤖 Prompt for AI Agents
In src/api/home/dateTimes.ts around lines 14 to 17, the getDateTimeStats
function lacks error handling; wrap the axios call in a try-catch, ensure the
catch logs the error (using the same logger or pattern used by
getMonthlyDatePlaceStats) and either rethrow the error or return the same
fallback value/shape that the other function returns on failure to keep behavior
consistent across the module.

8 changes: 8 additions & 0 deletions src/api/home/keyword.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import type { TWeeklyKeywordResponse } from '../../types/home/keyword';
import { axiosInstance } from '../axiosInstance';

// 이번 주 인기 키워드 조회 API
export const getWeeklyKeywords = async (): Promise<TWeeklyKeywordResponse> => {
const { data } = await axiosInstance.get('/api/v1/logs/keyword/weekly');
return data;
};
8 changes: 8 additions & 0 deletions src/api/home/level.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import type { TUserGradeResponse } from '../../types/home/level';
import { axiosInstance } from '../axiosInstance';

// 사용자 등급 조회 API
export const getUserGrade = async (): Promise<TUserGradeResponse> => {
const { data } = await axiosInstance.get('/api/v1/members/grade');
return data;
Comment on lines +7 to +8
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Axios 제네릭으로 응답 타입 안전성 강화

응답 타입을 제네릭으로 명시하면 data의 타입 안정성이 올라갑니다.

아래처럼 변경을 권장합니다.

-    const { data } = await axiosInstance.get('/api/v1/members/grade');
+    const { data } = await axiosInstance.get<TUserGradeResponse>('/api/v1/members/grade');
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const { data } = await axiosInstance.get('/api/v1/members/grade');
return data;
const { data } = await axiosInstance.get<TUserGradeResponse>('/api/v1/members/grade');
return data;
🤖 Prompt for AI Agents
In src/api/home/level.ts around lines 6 to 7, the axios call returns an untyped
data object; change the call to use Axios generics to enforce response typing
(e.g., define or import the expected response interface for the grade endpoint
and call axiosInstance.get<GradeResponse>('/api/v1/members/grade')) so the
returned data is properly typed and downstream code gains compile-time safety.

};
8 changes: 8 additions & 0 deletions src/api/home/region.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import type { TPatchUserRegionRequest, TPatchUserRegionResponse } from '@/types/home/region';

import { axiosInstance } from '@/api/axiosInstance';

export const patchUserRegion = async ({ regionId }: TPatchUserRegionRequest): Promise<TPatchUserRegionResponse> => {
const { data } = await axiosInstance.patch('/api/v1/regions/users', { regionId });
return data;
};
Comment on lines +5 to +8
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Axios 제네릭으로 응답 타입 명시

응답 타입을 명확히 지정해 런타임 이슈를 컴파일 타임에 방지하는 것을 권장합니다.

 export const patchUserRegion = async ({ regionId }: TPatchUserRegionRequest): Promise<TPatchUserRegionResponse> => {
-    const { data } = await axiosInstance.patch('/api/v1/regions/users', { regionId });
+    const { data } = await axiosInstance.patch<TPatchUserRegionResponse>('/api/v1/regions/users', { regionId });
     return data;
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const patchUserRegion = async ({ regionId }: TPatchUserRegionRequest): Promise<TPatchUserRegionResponse> => {
const { data } = await axiosInstance.patch('/api/v1/regions/users', { regionId });
return data;
};
export const patchUserRegion = async ({ regionId }: TPatchUserRegionRequest): Promise<TPatchUserRegionResponse> => {
const { data } = await axiosInstance.patch<TPatchUserRegionResponse>('/api/v1/regions/users', { regionId });
return data;
};
🤖 Prompt for AI Agents
In src/api/home/region.ts around lines 5 to 8, the axios.patch call does not
specify a response generic which can hide type mismatches; update the call to
use axiosInstance.patch<TPatchUserRegionResponse>('/api/v1/regions/users', {
regionId }) so the returned data is typed as TPatchUserRegionResponse and the
function signature stays correct, ensuring compile-time checking of the response
shape.

21 changes: 21 additions & 0 deletions src/api/home/weather.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type {
TGetPrecipitationRequest,
TGetPrecipitationResponse,
TGetWeeklyWeatheerRecommendationRequest,
TGetWeeklyWeatheerRecommendationResponse,
} from '@/types/home/weather';

import { axiosInstance } from '../axiosInstance';

// 주간 날씨 추천 조회 API
export const getWeeklyWeatherRecommendation = async ({
regionId,
startDate,
}: TGetWeeklyWeatheerRecommendationRequest): Promise<TGetWeeklyWeatheerRecommendationResponse> => {
const { data } = await axiosInstance.get(`/api/v1/weather/${regionId}/weekly`, { params: { startDate: startDate } });
return data;
};
export const getPrecipitation = async ({ regionId, startDate }: TGetPrecipitationRequest): Promise<TGetPrecipitationResponse> => {
const { data } = await axiosInstance.get(`/api/v1/weather/${regionId}/precipitation`, { params: { startDate: startDate } });
return data;
};
3 changes: 1 addition & 2 deletions src/assets/icons/weather/rain.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions src/components/common/modalProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import DateCourseSearchFilterModal from '@/components/modal/dateCourseSearchFilt
import ErrorModal from '@/components/modal/errorModal';
import SettingsModal from '@/components/modal/SettingModal';

import RegionModal from '../modal/regionModal';

Comment on lines +9 to +10
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

경로 alias 일관성 유지 제안

다른 모달들은 절대 경로 alias('@/components/...')를 사용하고 있는데, RegionModal만 상대 경로를 사용합니다. 팀 규칙에 맞춰 alias로 통일하면 가독성과 유지보수성이 좋아집니다.

적용 예시:

-import RegionModal from '../modal/regionModal';
+import RegionModal from '@/components/modal/regionModal';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import RegionModal from '../modal/regionModal';
-import RegionModal from '../modal/regionModal';
+import RegionModal from '@/components/modal/regionModal';
🤖 Prompt for AI Agents
In src/components/common/modalProvider.tsx around lines 9-10, the import for
RegionModal uses a relative path while other modals use the project alias;
replace the relative import with the same alias style (e.g. import RegionModal
from '@/components/modal/regionModal') to keep path conventions consistent, and
ensure the aliased path matches the project’s tsconfig/webpack path mapping.

import useModalStore from '@/store/useModalStore';

// 모달 타입 정의 -> 만약 다른 모달을 추가하고 싶다면 여기에 타입을 추가하고, MODAL_COMPONENTS에 컴포넌트를 추가하면 됩니다.
Expand All @@ -15,13 +17,15 @@ export const MODAL_TYPES = {
DateCourseSearchFilterModal: 'DateCourseSearchFilterModal',
SettingsModal: 'SettingsModal', //설정 모달 추가
AlarmModal: 'AlarmModal',
RegionModal: 'RegionModal',
};

export const MODAL_COMPONENTS = {
[MODAL_TYPES.ErrorModal]: ErrorModal,
[MODAL_TYPES.DateCourseSearchFilterModal]: DateCourseSearchFilterModal,
[MODAL_TYPES.SettingsModal]: SettingsModal,
[MODAL_TYPES.AlarmModal]: AlarmModal,
[MODAL_TYPES.RegionModal]: RegionModal,
};
Comment on lines 23 to 29
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

MODAL_COMPONENTS에 명시적 타입 지정 권장

현재 ModalComponent의 타입이 느슨해 JSX 사용 시 추론이 깨질 수 있습니다. 컴포넌트 프로프 형식이 모두 onClosemodalProps를 받는 동일 인터페이스라면 명시적으로 매핑 타입을 지정해주세요.

예시(제안 코드):

import type { ComponentType } from 'react';

type ModalBaseProps = { onClose: () => void } & Record<string, any>;
export const MODAL_COMPONENTS: Record<ModalType, ComponentType<ModalBaseProps>> = {
  [MODAL_TYPES.ErrorModal]: ErrorModal,
  [MODAL_TYPES.DateCourseSearchFilterModal]: DateCourseSearchFilterModal,
  [MODAL_TYPES.SettingsModal]: SettingsModal,
  [MODAL_TYPES.AlarmModal]: AlarmModal,
  [MODAL_TYPES.RegionModal]: RegionModal,
};
🤖 Prompt for AI Agents
In src/components/common/modalProvider.tsx around lines 23 to 29, the
MODAL_COMPONENTS object lacks an explicit typed mapping which weakens JSX prop
inference; declare a ModalBaseProps type (e.g., { onClose: () => void } &
Record<string, any>), import React's ComponentType, ensure you have a
ModalType/ModalType union matching MODAL_TYPES keys, and annotate
MODAL_COMPONENTS as Record<ModalType, ComponentType<ModalBaseProps>> so each
modal component is typed to receive onClose and modalProps consistently.


export default function ModalProvider() {
Expand Down
8 changes: 6 additions & 2 deletions src/components/home/banner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,25 @@ const slides = [
title: '서울 성수동 : 옛것과 새로운 것이 교차하는 하루',
description: '1960년대부터 조성된 오래된 공장 건물과 최근 벽돌 건물들의 분위기',
tags: ['#활발한 활동', '#레트로 감성', '#서울 핫플'],
img: scroll,
},
{
title: '한강 자전거 데이트 : 바람 따라 달리는 낭만',
description: '도심 속 자연을 만끽하며 힐링 타임',
tags: ['#운동 데이트', '#자연과 함께', '#저녁노을'],
img: scroll,
},
{
title: '이태원 세계 음식 투어 : 입 안 가득 여행',
description: '세계 각국의 맛을 한 자리에서 즐기기',
tags: ['#미식가 커플', '#이국적인 분위기', '#도심 속 여행'],
img: scroll,
},
{
title: '북촌 한옥마을 산책 : 전통의 미를 따라 걷기',
description: '골목골목 숨어있는 사진 명소',
tags: ['#한옥', '#조용한 산책', '#전통과 현대'],
img: scroll,
},
];
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

중복된 img 필드 제거 + 기본 이미지 fallback으로 단순화

모든 슬라이드에 동일한 이미지(scroll)를 반복 지정하는 대신, 렌더링 시 기본 이미지를 fallback으로 사용하면 중복을 줄일 수 있습니다.

아래처럼 중복된 속성을 제거하세요:

-        img: scroll,
...
-        img: scroll,
...
-        img: scroll,
...
-        img: scroll,
🤖 Prompt for AI Agents
In src/components/home/banner.tsx around lines 15 to 35, several slide objects
repeatedly set the same img: scroll value; remove the duplicated img properties
from those slide objects and leave image out of the data, then update the
banner/slider render logic to use a single default/fallback image when item.img
is undefined or falsy (e.g., item.img || DEFAULT_IMAGE). Ensure any TypeScript
types/interfaces for slide items allow img to be optional.


Expand All @@ -52,11 +56,11 @@ function Banner() {
setCurrentIndex((prevIndex) => (prevIndex + 1) % slides.length);
};

const { title, description, tags } = slides[currentIndex];
const { title, description, tags, img } = slides[currentIndex];

return (
<div className="relative w-full">
<img src={scroll} alt="배너" className="w-full h-[450px] object-cover" />
<img src={img} alt="배너" className="w-full h-[450px] object-cover" />
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

배너 이미지에 기본 fallback 적용 + 접근성 향상(alt 동적화)

  • 기본 이미지를 사용하도록 fallback을 적용하면 데이터가 없는 경우에도 안전합니다.
  • alt를 제목 기반으로 지정하면 스크린리더 접근성이 개선됩니다.
-    const { title, description, tags, img } = slides[currentIndex];
+    const { title, description, tags } = slides[currentIndex];
-            <img src={img} alt="배너" className="w-full h-[450px] object-cover" />
+            <img src={slides[currentIndex].img ?? scroll} alt={title} className="w-full h-[450px] object-cover" />
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const { title, description, tags, img } = slides[currentIndex];
return (
<div className="relative w-full">
<img src={scroll} alt="배너" className="w-full h-[450px] object-cover" />
<img src={img} alt="배너" className="w-full h-[450px] object-cover" />
const { title, description, tags } = slides[currentIndex];
return (
<div className="relative w-full">
<img
src={slides[currentIndex].img ?? scroll}
alt={title}
className="w-full h-[450px] object-cover"
/>
🤖 Prompt for AI Agents
In src/components/home/banner.tsx around lines 59 to 63, the banner currently
uses slides[currentIndex].img directly and a hardcoded alt; update it to safely
fall back to a default image when img is missing (e.g., use a constant
DEFAULT_BANNER_IMG or require/import a fallback asset) and make the alt
attribute dynamic based on the slide title (e.g., alt={`${title || '배너'}`) or a
localized default) to improve accessibility; ensure the fallback logic handles
empty strings/null/undefined and preserve the same sizing/classes.


{/* 내용 */}
<div className="absolute inset-0 flex flex-col justify-start px-4 sm:px-12 py-10 text-white z-10">
Expand Down
19 changes: 17 additions & 2 deletions src/components/home/dateCourseStore.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
import React from 'react';
import { useNavigate } from 'react-router-dom';

import { useDateCourseSavedCount } from '@/hooks/home/useDateCourseStats';

import MainCard from './mainCard';

import ArchiveBlank from '@/assets/icons/Archive_Blank.svg?react';

function DateCourseStore() {
const navigate = useNavigate();
const { data, isLoading, error } = useDateCourseSavedCount();
if (error) {
navigate('/error');
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

렌더 단계에서 navigate 호출은 부작용이므로 useEffect로 이동하세요

렌더 중 navigate('/error') 호출은 예기치 않은 재렌더/히스토리 누적을 유발할 수 있습니다. useEffect로 옮기고, 화면 깜빡임 방지를 위해 조기 반환을 추가하세요.

적용 예시(diff):

-    if (error) {
-        navigate('/error');
-    }
+    React.useEffect(() => {
+        if (error) {
+            navigate('/error', { replace: true });
+        }
+    }, [error, navigate]);
+    if (error) {
+        return null;
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (error) {
navigate('/error');
}
React.useEffect(() => {
if (error) {
navigate('/error', { replace: true });
}
}, [error, navigate]);
if (error) {
return null;
}
🤖 Prompt for AI Agents
In src/components/home/dateCourseStore.tsx around lines 13-15, the code calls
navigate('/error') directly during render which is a side-effect; move that
navigation into a useEffect that watches the error state and calls navigate only
when error becomes true, and add an early return (e.g., return null or a
loading/empty placeholder) when error is present to avoid a render flicker and
duplicate history entries; ensure the useEffect dependency array includes the
error (and navigate if not stable) so navigation runs only when error changes.

return (
<MainCard>
<div className="flex flex-col px-4 sm:px-8 lg:px-[20px] py-8 lg:py-[28px] h-full justify-center">
Expand All @@ -11,11 +21,16 @@ function DateCourseStore() {
</div>
<div className="flex text-sm sm:text-base lg:text-m bold-medium text-[#616161] mb-1">내 데이트 코스를</div>
<div className="flex gap-1 items-center">
<div className="text-lg sm:text-xl font-bold text-primary-700 whitespace-nowrap">2,345명</div>
{isLoading ? (
<div className="text-lg sm:text-xl font-bold text-primary-700 whitespace-nowrap">로딩...</div>
) : (
<div className="text-lg sm:text-xl font-bold text-primary-700 whitespace-nowrap">{data?.result.count}명</div>
)}
Comment on lines +22 to +26
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

데이터 미도착 시 'undefined명' 노출 가능성 및 숫자 포매팅 개선

데이터가 일시적으로 없을 때 undefined명이 표시될 수 있습니다. 기본값과 천 단위 구분을 적용해 가독성을 높이세요.

적용 예시(diff):

-                        <div className="text-lg sm:text-xl font-bold text-primary-700 whitespace-nowrap">{data?.result.count}명</div>
+                        <div className="text-lg sm:text-xl font-bold text-primary-700 whitespace-nowrap">
+                            {(data?.result.count ?? 0).toLocaleString()}명
+                        </div>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{isLoading ? (
<div className="text-lg sm:text-xl font-bold text-primary-700 whitespace-nowrap">로딩...</div>
) : (
<div className="text-lg sm:text-xl font-bold text-primary-700 whitespace-nowrap">{data?.result.count}</div>
)}
{isLoading ? (
<div className="text-lg sm:text-xl font-bold text-primary-700 whitespace-nowrap">
로딩...
</div>
) : (
<div className="text-lg sm:text-xl font-bold text-primary-700 whitespace-nowrap">
{(data?.result.count ?? 0).toLocaleString()}
</div>
)}
🤖 Prompt for AI Agents
In src/components/home/dateCourseStore.tsx around lines 24 to 28, the count
display can show "undefined명" when data is missing and lacks thousand
separators; to fix, derive a safe numeric value (e.g., const count =
data?.result?.count ?? 0) and render the formatted string using a locale-aware
formatter (e.g., Intl.NumberFormat or toLocaleString) so the UI shows "0명" when
absent and numbers with thousand separators.

<div className="text-sm sm:text-base lg:text-m bold-medium text-[#616161] whitespace-nowrap">이 저장했어요.</div>
</div>
</div>
</MainCard>
);
}
export default DateCourseStore;

export default React.memo(DateCourseStore);
44 changes: 23 additions & 21 deletions src/components/home/dateLocation.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,36 @@
import React, { useMemo } from 'react';

import { useMontlyPlaceStates } from '@/hooks/home/useDatePlaceStates';

import MainCard from '@/components/home/mainCard';

function DateLocation() {
const { data } = useMontlyPlaceStates();
const maxCount = useMemo(() => {
return data?.result?.datePlaceLogList?.reduce((max, cur) => Math.max(max, cur.count), 0) ?? 0;
}, [data]);
return (
<MainCard>
<div className="py-[28px] flex flex-col">
<div className="text-xl font-bold text-[#616161] mb-6">WithTime에 등록된 데이트 장소 수</div>
<div className="flex items-end gap-8 w-full justify-center">
<div className="flex flex-col items-center">
<span className="text-xs text-default-gray-500 mb-1">230</span>
<div className="h-16 w-10 bg-default-gray-400 mb-2 flex items-start justify-center" />
<div className="text-default-gray-500 mt-1">2022</div>
</div>
<div className="flex flex-col items-center">
<span className="text-xs text-default-gray-500 mb-1">430</span>
<div className="h-24 w-10 bg-default-gray-400 mb-2 flex items-start justify-center" />
<div className="text-default-gray-500 mt-1">2023</div>
</div>
<div className="flex flex-col items-center">
<span className="text-xs text-default-gray-500 mb-1">830</span>
<div className="h-36 w-10 bg-default-gray-400 mb-2 flex items-start justify-center" />
<div className="text-default-gray-500 mt-1">2024</div>
</div>
<div className="flex flex-col items-center">
<span className="text-xs text-default-gray-500 mb-1">1,230</span>
<div className="h-48 w-10 bg-default-gray-400 mb-2 flex items-start justify-center" />
<div className="text-default-gray-500 mt-1">2025</div>
</div>
{data?.result.datePlaceLogList.map((graph, idx) => {
// 비율 계산
const height = maxCount ? (graph.count / maxCount) * 200 : 0; // 최대 높이 200px 기준
return (
<div className="flex flex-col items-center" key={idx}>
<span className="text-xs text-default-gray-500 mb-1">{graph.count}</span>
<div
className="w-10 bg-default-gray-400 mb-2 flex items-start justify-center transition-all duration-300"
style={{ height: `${height}px` }}
/>
<div className="text-default-gray-500 mt-1">{graph.month}</div>
</div>
);
})}
</div>
</div>
</MainCard>
);
}
export default DateLocation;
export default React.memo(DateLocation);
Loading