From 20d0e7c1b67e65542394954bcd0dc7008a3a7e73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=97=B0=EC=A7=84?= Date: Thu, 14 Aug 2025 02:08:11 +0900 Subject: [PATCH 01/17] =?UTF-8?q?feat:=20API=20=EC=97=B0=EA=B2=B0=20?= =?UTF-8?q?=EB=B0=8F=20=EC=A0=84=EC=97=AD=EA=B4=80=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/course/course.ts | 94 +++++++- src/app/routeChangeReset.tsx | 31 +++ src/components/dateCourse/dateCourse.tsx | 43 ++-- .../dateCourseSearchFilterOption.tsx | 50 +++-- src/components/dateCourse/dateKeyword.tsx | 4 +- src/components/dateCourse/placeButton.tsx | 2 +- .../modal/dateCourseSearchFilterModal.tsx | 203 ++++++++++-------- src/constants/dateCourseQuestion.ts | 7 + src/hooks/course/useBookmark.ts | 9 + src/hooks/course/useCourse.ts | 10 + src/layout/layout.tsx | 3 + src/pages/dateCourse/BookmarkedDateCourse.tsx | 42 +++- src/pages/dateCourse/CoursePage.tsx | 40 +++- src/pages/dateCourse/FindDateCourse.tsx | 39 +++- src/pages/dateCourse/MakeCourseResult.tsx | 40 +++- src/pages/dateCourse/MakeCourseStep.tsx | 158 ++++++++------ src/store/useFilterStore.ts | 37 ++++ src/types/dateCourse/dateCourse.ts | 84 ++++++++ src/utils/dateCourseValidation.tsx | 43 ++-- 19 files changed, 710 insertions(+), 229 deletions(-) create mode 100644 src/app/routeChangeReset.tsx create mode 100644 src/hooks/course/useBookmark.ts create mode 100644 src/hooks/course/useCourse.ts create mode 100644 src/store/useFilterStore.ts diff --git a/src/api/course/course.ts b/src/api/course/course.ts index c1ec404..19d3478 100644 --- a/src/api/course/course.ts +++ b/src/api/course/course.ts @@ -1,4 +1,17 @@ -import type { TSearchRegionResponse, TSearchRegionValues } from '@/types/dateCourse/dateCourse'; +import type { + TDeleteBookmarkRequest, + TDeleteBookmarkResponse, + TGetBookmarkedDateCourseRequest, + TGetBookmarkedDateCourseResponse, + TGetDateCourseRequest, + TGetDateCourseResponse, + TPostBookmarkRequest, + TPostBookmarkResponse, + TPostDateCourseRequest, + TPostDateCourseResponse, + TSearchRegionResponse, + TSearchRegionValues, +} from '@/types/dateCourse/dateCourse'; import { axiosInstance } from '@/api/axiosInstance'; @@ -10,3 +23,82 @@ export const searchRegion = async ({ keyword }: TSearchRegionValues): Promise => { + const { data } = await axiosInstance.post('/api/v1/date-courses/', { + budget, + datePlaces, + mealPlan, + transportation, + userPreferredKeywords, + startTime, + }); + return data; +}; + +export const postBookmark = async ({ dateCourseId }: TPostBookmarkRequest): Promise => { + const { data } = await axiosInstance.post(`/api/v1/date-courses/${dateCourseId}/bookmarks`); + return data; +}; + +export const deleteBookmark = async ({ dateCourseId }: TDeleteBookmarkRequest): Promise => { + const { data } = await axiosInstance.delete(`/api/v1/date-courses/${dateCourseId}/bookmarks`); + return data; +}; + +export const getDateCourse = async ({ + budget, + datePlaces, + mealTypes, + transportation, + userPreferredKeywords, + page, + size, +}: TGetDateCourseRequest): Promise => { + const { data } = await axiosInstance.post('/api/v1/date-courses/search', { + params: { + page, + size, + }, + data: { + budget, + datePlaces, + mealTypes, + transportation, + userPreferredKeywords, + }, + }); + return data; +}; + +export const getBookmarkedDateCourse = async ({ + budget, + datePlaces, + mealTypes, + transportation, + userPreferredKeywords, + page, + size, +}: TGetBookmarkedDateCourseRequest): Promise => { + const { data } = await axiosInstance.post('/api/v1/date-courses/search', { + params: { + page, + size, + }, + data: { + budget, + datePlaces, + mealTypes, + transportation, + userPreferredKeywords, + }, + }); + return data; +}; diff --git a/src/app/routeChangeReset.tsx b/src/app/routeChangeReset.tsx new file mode 100644 index 0000000..5c63b99 --- /dev/null +++ b/src/app/routeChangeReset.tsx @@ -0,0 +1,31 @@ +// src/app/RouteScopeReset.tsx +import { useEffect, useRef } from 'react'; +import { useLocation } from 'react-router-dom'; + +import useFilterStore from '@/store/useFilterStore'; + +const SCOPES = ['/makeCourse', '/dateCourse', '/findCourse'] as const; +type TScope = (typeof SCOPES)[number] | null; + +function getScope(pathname: string): TScope { + // '/makeCourse' 또는 '/makeCourse/...' 형태 매칭 + const hit = SCOPES.find((s) => pathname === s || pathname.startsWith(s + '/')); + return hit ?? null; +} + +export default function RouteScopeReset() { + const { pathname } = useLocation(); + const reset = useFilterStore((s) => s.reset); + const prevScopeRef = useRef(getScope(pathname)); + + useEffect(() => { + const nowScope = getScope(pathname); + if (prevScopeRef.current !== nowScope) { + // 스코프가 바뀌는 순간(스코프 밖↔안, 스코프 A↔B)만 초기화 + reset(); + prevScopeRef.current = nowScope; + } + }, [pathname, reset]); + + return null; +} diff --git a/src/components/dateCourse/dateCourse.tsx b/src/components/dateCourse/dateCourse.tsx index cc2b5f5..b548719 100644 --- a/src/components/dateCourse/dateCourse.tsx +++ b/src/components/dateCourse/dateCourse.tsx @@ -1,5 +1,7 @@ import { useEffect, useRef, useState } from 'react'; +import type { TDateCourse } from '@/types/dateCourse/dateCourse'; + import Info from './info'; import Timeline from './timeline'; import DeleteBookmarkModal from '../modal/deleteBookmarkModal'; @@ -8,19 +10,23 @@ import BookmarkBlank from '@/assets/icons/Bookmark_Blank.svg?react'; import BookmarkFill from '@/assets/icons/Bookmark_Fill.svg?react'; import KeyboardArrowDown from '@/assets/icons/keyboard_arrow_down_False.svg?react'; -function DateCourse({ defaultOpen = false }: { defaultOpen?: boolean }) { +type TDateCourseProps = TDateCourse & { + defaultOpen?: boolean; +}; + +function DateCourse({ defaultOpen = false, name, datePlaces }: TDateCourseProps) { const [open, setOpen] = useState(defaultOpen || false); const [openEdit, setOpenEdit] = useState(false); const [openModal, setOpenModal] = useState(false); const [isBookmarked, setIsBookmarked] = useState(false); const moreRef = useRef(null); + const clickBookmark = () => { if (isBookmarked) { setOpenModal(true); } else { setIsBookmarked(!isBookmarked); } - // console.log('북마크 해제'); }; useEffect(() => { @@ -29,7 +35,6 @@ function DateCourse({ defaultOpen = false }: { defaultOpen?: boolean }) { setOpenEdit(false); } }; - document.addEventListener('mousedown', handleClickOutside); return () => document.removeEventListener('mousedown', handleClickOutside); }, [openEdit]); @@ -46,7 +51,8 @@ function DateCourse({ defaultOpen = false }: { defaultOpen?: boolean }) { {open ? : }
- 2025.06.01 데이트코스 + {name} + 데이트 코스
@@ -63,22 +69,19 @@ function DateCourse({ defaultOpen = false }: { defaultOpen?: boolean }) {
- - + {datePlaces.map((place, idx) => { + return ( + + ); + })}
diff --git a/src/components/dateCourse/dateCourseSearchFilterOption.tsx b/src/components/dateCourse/dateCourseSearchFilterOption.tsx index 38b8c80..ef429c2 100644 --- a/src/components/dateCourse/dateCourseSearchFilterOption.tsx +++ b/src/components/dateCourse/dateCourseSearchFilterOption.tsx @@ -12,7 +12,17 @@ import EditableInputBox from '../common/EditableInputBox'; import Calendar from '@/assets/icons/calendar_Blank.svg?react'; -export default function DateCourseSearchFilterOption({ options, type, value, onChange, title, subTitle, errorMessage }: TDateCourseSearchFilterOption) { +export default function DateCourseSearchFilterOption({ + options, + apiRequestValue, + type, + value, + onChange, + title, + subTitle, + errorMessage, + autoInit, +}: TDateCourseSearchFilterOption) { const now = new Date(); const defaultDate = now.toISOString().split('T')[0]; // '2025-07-17' @@ -25,7 +35,9 @@ export default function DateCourseSearchFilterOption({ options, type, value, onC const [inputValue, setInputValue] = useState(''); useEffect(() => { - onChange(`${date} ${time}`); + if (type === 'time' && autoInit && (value == null || value === '')) { + onChange(`${date} ${time}`); + } }, []); const handleDateClick = () => { @@ -37,7 +49,7 @@ export default function DateCourseSearchFilterOption({ options, type, value, onC }; const handleDeletePlaceOption = (val: string) => { - if (Array.isArray(value)) { + if (Array.isArray(value) && type === 'search') { onChange(value.filter((v) => v !== val)); } }; @@ -54,6 +66,18 @@ export default function DateCourseSearchFilterOption({ options, type, value, onC refetch(); }; + let items = options?.map((label, idx) => ({ + label, + value: apiRequestValue && apiRequestValue[idx], + })); + + useEffect(() => { + items = options?.map((label, idx) => ({ + label, + value: apiRequestValue && apiRequestValue[idx], + })); + }, [options]); + return (
@@ -63,20 +87,20 @@ export default function DateCourseSearchFilterOption({ options, type, value, onC
{errorMessage}
{type === 'choice' && - options?.map((option, idx) => ( - onChange(option)} /> - ))} + items?.map(({ label, value: apiValue }, idx) => { + return onChange(apiValue!)} />; + })} {type === 'choices' && - options?.map((option, idx) => { + items?.map(({ label, value: apiValue }, idx) => { const current = Array.isArray(value) ? value : []; - const isSelected = current.includes(option); + const isSelected = current.includes(apiValue!); return ( onChange(isSelected ? current.filter((v) => v !== option) : [...current, option])} + onClick={() => onChange(isSelected ? current.filter((v) => v !== apiValue) : [...current, apiValue!])} /> ); })} @@ -88,7 +112,7 @@ export default function DateCourseSearchFilterOption({ options, type, value, onC mode="search" onSearchClick={handleSearch} placeholder="ex: 서울시 강남구" - className="w-full" + className="!min-w-full" value={inputValue} onChange={handleInputChange} /> @@ -149,7 +173,7 @@ export default function DateCourseSearchFilterOption({ options, type, value, onC onChange={(e) => { const val = e.target.value; setDate(val); - if (time) onChange(`${val} ${time}`); + if (time) onChange(`${val}T${time}:00`); }} className="absolute top-0 left-0 w-full h-full opacity-0" /> @@ -164,7 +188,7 @@ export default function DateCourseSearchFilterOption({ options, type, value, onC onChange={(e) => { const val = e.target.value; setTime(val); - if (date) onChange(`${date} ${val}`); + if (date) onChange(`${date}T${val}:00`); }} className="absolute top-0 left-0 w-full h-full opacity-0" /> diff --git a/src/components/dateCourse/dateKeyword.tsx b/src/components/dateCourse/dateKeyword.tsx index 961556c..44fa25a 100644 --- a/src/components/dateCourse/dateKeyword.tsx +++ b/src/components/dateCourse/dateKeyword.tsx @@ -17,12 +17,12 @@ export default function DateKeyword({ category, tags, setState, state }: TDat {tags.map((tag) => { return ( { - toggleItem(tag.label); + toggleItem(tag.code); }} /> ); diff --git a/src/components/dateCourse/placeButton.tsx b/src/components/dateCourse/placeButton.tsx index a84879b..55126c9 100644 --- a/src/components/dateCourse/placeButton.tsx +++ b/src/components/dateCourse/placeButton.tsx @@ -6,7 +6,7 @@ export default function PlaceButton({ placeName, onClick }: { placeName: string;
-
{placeName}
+
{placeName}
diff --git a/src/components/modal/dateCourseSearchFilterModal.tsx b/src/components/modal/dateCourseSearchFilterModal.tsx index 17f7163..49597e5 100644 --- a/src/components/modal/dateCourseSearchFilterModal.tsx +++ b/src/components/modal/dateCourseSearchFilterModal.tsx @@ -1,4 +1,5 @@ -import { useEffect, useState } from 'react'; +// DateCourseSearchFilterModal.tsx +import { useEffect, useMemo, useState } from 'react'; import { DateCourseQuestion } from '@/constants/dateCourseQuestion'; @@ -11,114 +12,136 @@ import { TotalTimeMealValidation, } from '@/utils/dateCourseValidation'; +import useCourse from '@/hooks/course/useCourse'; + import Button from '../common/Button'; import Modal from '../common/modal'; import DateCourseSearchFilterOption from '../dateCourse/dateCourseSearchFilterOption'; -type TDateCourseSearchFilterModalProps = { - onClose: () => void; -}; - -interface IQuestion { - id: number; - title: string; - options: string[] | null; - keyword: string | null; - subTitle: string | null; - filterTitle: string; - type: 'choice' | 'search' | 'time' | 'choices' | 'keyword'; -} +import useFilterStore from '@/store/useFilterStore'; -// ✅ 질문 리스트 (0~6개만 필터링) -const Questions: IQuestion[] = Array.isArray(DateCourseQuestion) - ? DateCourseQuestion.slice(0, 7).map((q) => ({ - ...q, - type: q.type as IQuestion['type'], - })) - : []; +type TProps = { onClose: () => void }; -export default function DateCourseSearchFilterModal({ onClose }: TDateCourseSearchFilterModalProps) { - const [answers, setAnswers] = useState<(string | string[] | null)[]>(Array(7).fill(null)); - const num = 5325; // 예시용 +export default function DateCourseSearchFilterModal({ onClose }: TProps) { + const { setField, ...filters } = useFilterStore(); const [errorMessages, setErrorMessages] = useState(Array(7).fill('')); + const { useGetBookmarkedCourse } = useCourse(); + const { mutate: getBookmarkedDateCourse } = useGetBookmarkedCourse; + const { budget, datePlaces, dateDurationTime, startTime, mealTypes, transportation, userPreferredKeywords } = useFilterStore(); + const Questions = useMemo( + () => + (Array.isArray(DateCourseQuestion) ? DateCourseQuestion.slice(0, 7) : []) + .map((q) => ({ ...q, type: q.type as 'choice' | 'search' | 'time' | 'choices' | 'keyword' })) + .filter((q) => q.filterTitle !== ''), + [], + ); - const handleSearch = () => { - console.log('선택된 필터:', answers); - onClose(); + const valueByIndex = (idx: number) => { + switch (idx) { + case 0: + return filters.budget; + case 1: + return filters.datePlaces; + case 2: + return filters.dateDurationTime; + case 3: + return filters.mealTypes; + case 4: + return filters.transportation; + case 5: + return filters.userPreferredKeywords; + case 6: + return filters.startTime; + default: + return null; + } }; - const checkError = () => { - const newErrors = [...errorMessages]; - - newErrors[0] = - BudgetTimeValidation({ - budget: answers[0] as string, - totalTime: answers[2] as string, - }) || ''; - - newErrors[2] = - TotalTimeMealValidation({ - totalTime: answers[2] as string, - meal: Array.isArray(answers[3]) ? answers[3] : [], - }) || ''; - - newErrors[3] = - KeywordMealValidation({ - meal: Array.isArray(answers[3]) ? answers[3] : [], - keywords: Array.isArray(answers[5]) ? answers[5] : [], - }) || ''; - - newErrors[5] = - KeywordGroupOverValidation({ - keywords: Array.isArray(answers[5]) ? answers[5] : [], - }) || ''; - - newErrors[6] = - MealTimeValidation({ - meal: Array.isArray(answers[3]) ? answers[3] : [], - time: answers[6] as string, - totalTime: answers[2] as string, - }) || - DateTimeStartValidation({ - time: answers[6] as string, - totalTime: answers[2] as string, - }) || + const runValidation = () => { + const errs = [...errorMessages]; + errs[0] = BudgetTimeValidation({ budget: filters.budget as any, totalTime: filters.dateDurationTime as any }) || ''; + errs[2] = TotalTimeMealValidation({ totalTime: filters.dateDurationTime as any, meal: filters.mealTypes ?? [] }) || ''; + errs[3] = KeywordMealValidation({ meal: filters.mealTypes ?? [], keywords: filters.userPreferredKeywords ?? [] }) || ''; + errs[5] = KeywordGroupOverValidation({ keywords: filters.userPreferredKeywords ?? [] }) || ''; + errs[6] = + MealTimeValidation({ meal: filters.mealTypes ?? [], time: filters.startTime as any, totalTime: filters.dateDurationTime as any }) || + DateTimeStartValidation({ time: filters.startTime as any, totalTime: filters.dateDurationTime as any }) || ''; - - setErrorMessages(newErrors); + setErrorMessages(errs); + return errs.every((e) => !e); }; + const updateByIndex = (idx: number, v: any) => { + const apply = () => { + switch (idx) { + case 0: + setField('budget', v ?? null); + break; + case 1: + setField('datePlaces', Array.isArray(v) ? v : []); + break; + case 2: + setField('dateDurationTime', v ?? null); + break; + case 3: + setField('mealTypes', Array.isArray(v) ? v : []); + break; + case 4: + setField('transportation', v ?? null); + break; + case 5: + setField('userPreferredKeywords', Array.isArray(v) ? v : []); + break; + case 6: + setField('startTime', v ?? null); + break; + } + }; + + apply(); + runValidation(); + }; useEffect(() => { - checkError(); - }, [answers]); + getBookmarkedDateCourse( + { + page: 1, + size: 5, + budget: filters.budget, + dateDurationTime: filters.dateDurationTime, + datePlaces: filters.datePlaces, + mealTypes: filters.datePlaces, + transportation: filters.transportation, + userPreferredKeywords: filters.userPreferredKeywords, + startTime: filters.startTime, + }, + { + onSuccess: () => { + // 추후 데이터 추가되면 총 개수 불러와서 밑에 추가할 예정 + }, + }, + ); + }, [budget, datePlaces, dateDurationTime, mealTypes, transportation, userPreferredKeywords, startTime]); return (
- {Questions.map( - (question, idx) => - question.filterTitle !== '' && ( - { - setAnswers((prev) => { - const updated = [...prev]; - updated[idx] = value; - return updated; - }); - }} - type={question.type} - errorMessage={errorMessages[idx] ?? ''} - /> - ), - )} + {Questions.map((q, idx) => ( + updateByIndex(idx, v)} // ← 즉시 적용 + type={q.type} + apiRequestValue={q.apiRequestValue} + errorMessage={errorMessages[idx] ?? ''} + /> + ))} +
-
diff --git a/src/constants/dateCourseQuestion.ts b/src/constants/dateCourseQuestion.ts index c429032..36c7603 100644 --- a/src/constants/dateCourseQuestion.ts +++ b/src/constants/dateCourseQuestion.ts @@ -6,6 +6,7 @@ export const DateCourseQuestion = [ subTitle: '(1인당)', keyword: '예산 범위', options: ['1만원 이하', '1-2만원', '2-3만원', '3만원 이상'], + apiRequestValue: ['UNDER_10K', 'FROM_10K_TO_20K', 'FROM_20K_TO_30K', 'OVER_30K'], type: 'choice', }, { @@ -15,6 +16,7 @@ export const DateCourseQuestion = [ keyword: '만날 장소', options: null, type: 'search', + apiRequestValue: null, filterTitle: '만날 장소', }, { @@ -23,6 +25,7 @@ export const DateCourseQuestion = [ subTitle: '(1개만 선택 가능)', keyword: '데이트 시간', options: ['1-2시간', '3-4시간', '반나절', '하루 종일'], + apiRequestValue: ['ONETOTWO', 'THREETOFOUR', 'HALFDAY', 'ALLDAY'], type: 'choice', filterTitle: '데이트 시간', }, @@ -32,6 +35,7 @@ export const DateCourseQuestion = [ subTitle: null, keyword: '식사 구성', options: ['아침', '점심', '저녁'], + apiRequestValue: ['BREAKFAST', 'LUNCH', 'DINNER'], type: 'choices', filterTitle: '식사 구성', }, @@ -41,6 +45,7 @@ export const DateCourseQuestion = [ subTitle: null, keyword: '이동 수단', options: ['도보', '자차', '대중교통'], + apiRequestValue: ['WALK', 'CAR', 'PUBLICTRAN'], type: 'choice', filterTitle: '', }, @@ -50,6 +55,7 @@ export const DateCourseQuestion = [ subTitle: null, keyword: '데이트 키워드', options: null, + apiRequestValue: null, type: 'keyword', filterTitle: '데이트 키워드', }, @@ -59,6 +65,7 @@ export const DateCourseQuestion = [ subTitle: '24:00 기준', keyword: null, options: null, + apiRequestValue: null, type: 'time', filterTitle: '만날 시간', }, diff --git a/src/hooks/course/useBookmark.ts b/src/hooks/course/useBookmark.ts new file mode 100644 index 0000000..fa2ac64 --- /dev/null +++ b/src/hooks/course/useBookmark.ts @@ -0,0 +1,9 @@ +import { useCoreMutation } from '../customQuery'; + +import { deleteBookmark, postBookmark } from '@/api/course/course'; + +export default function useBookmark() { + const usePostBookmark = useCoreMutation(postBookmark); + const useDeleteBookmark = useCoreMutation(deleteBookmark); + return { usePostBookmark, useDeleteBookmark }; +} diff --git a/src/hooks/course/useCourse.ts b/src/hooks/course/useCourse.ts new file mode 100644 index 0000000..de640f0 --- /dev/null +++ b/src/hooks/course/useCourse.ts @@ -0,0 +1,10 @@ +import { useCoreMutation } from '../customQuery'; + +import { getBookmarkedDateCourse, getDateCourse, postDateCourse } from '@/api/course/course'; + +export default function useCourse() { + const useMakeCourse = useCoreMutation(postDateCourse); + const useGetCourse = useCoreMutation(getDateCourse); + const useGetBookmarkedCourse = useCoreMutation(getBookmarkedDateCourse); + return { useMakeCourse, useGetBookmarkedCourse, useGetCourse }; +} diff --git a/src/layout/layout.tsx b/src/layout/layout.tsx index 844b1af..6ff1399 100644 --- a/src/layout/layout.tsx +++ b/src/layout/layout.tsx @@ -3,12 +3,15 @@ import { Outlet } from 'react-router-dom'; import Footer from '@/components/layout/Footer'; import Header from '@/components/layout/Header'; +import RouteChangeReset from '@/app/routeChangeReset'; + function Layout() { return (
+
); } diff --git a/src/pages/dateCourse/BookmarkedDateCourse.tsx b/src/pages/dateCourse/BookmarkedDateCourse.tsx index d1a1893..7250c26 100644 --- a/src/pages/dateCourse/BookmarkedDateCourse.tsx +++ b/src/pages/dateCourse/BookmarkedDateCourse.tsx @@ -1,15 +1,45 @@ -import { useState } from 'react'; +import { useEffect, useState } from 'react'; + +import type { TGetBookmarkedDateCourseResponse } from '@/types/dateCourse/dateCourse'; + +import useCourse from '@/hooks/course/useCourse'; import { MODAL_TYPES } from '@/components/common/modalProvider'; import Navigator from '@/components/common/navigator'; import DateCourse from '@/components/dateCourse/dateCourse'; import Filter from '@/assets/icons/filter_Blank.svg?react'; +import useFilterStore from '@/store/useFilterStore'; import useModalStore from '@/store/useModalStore'; function BookmarkedDateCourse() { const [current, setCurrent] = useState(1); + const [courseData, setCourseData] = useState(); + const { openModal } = useModalStore(); + const { useGetBookmarkedCourse } = useCourse(); + const { budget, datePlaces, dateDurationTime, startTime, mealTypes, transportation, userPreferredKeywords } = useFilterStore(); + const { mutate: getBookmarkedDateCourse } = useGetBookmarkedCourse; + useEffect(() => { + getBookmarkedDateCourse( + { + page: current, + size: 5, + budget, + dateDurationTime, + datePlaces, + mealTypes, + transportation, + userPreferredKeywords, + startTime, + }, + { + onSuccess: (data) => { + setCourseData(data); + }, + }, + ); + }, [current]); return (
@@ -25,13 +55,11 @@ function BookmarkedDateCourse() {
- - - - - + {courseData?.result.dateCourseList.map((course) => { + return ; + })}
- +
diff --git a/src/pages/dateCourse/CoursePage.tsx b/src/pages/dateCourse/CoursePage.tsx index 7ac8f60..f9febfa 100644 --- a/src/pages/dateCourse/CoursePage.tsx +++ b/src/pages/dateCourse/CoursePage.tsx @@ -1,18 +1,48 @@ -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import { useNavigate } from 'react-router-dom'; +import type { TGetBookmarkedDateCourseResponse } from '@/types/dateCourse/dateCourse'; + +import useCourse from '@/hooks/course/useCourse'; + import { MODAL_TYPES } from '@/components/common/modalProvider'; import Navigator from '@/components/common/navigator'; import DateCourse from '@/components/dateCourse/dateCourse'; import FileTray from '@/assets/icons/file_tray_empty_Fill.svg?react'; import Filter from '@/assets/icons/filter_Blank.svg?react'; +import useFilterStore from '@/store/useFilterStore'; import useModalStore from '@/store/useModalStore'; export default function Course() { const navigate = useNavigate(); const { openModal } = useModalStore(); const [current, setCurrent] = useState(1); + const [courseData, setCourseData] = useState(); + + const { useGetBookmarkedCourse } = useCourse(); + const { budget, datePlaces, dateDurationTime, startTime, mealTypes, transportation, userPreferredKeywords } = useFilterStore(); + const { mutate: getBookmarkedDateCourse } = useGetBookmarkedCourse; + useEffect(() => { + getBookmarkedDateCourse( + { + page: current, + size: 5, + budget, + dateDurationTime, + datePlaces, + mealTypes, + transportation, + userPreferredKeywords, + startTime, + }, + { + onSuccess: (data) => { + setCourseData(data); + }, + }, + ); + }, [current]); return (
@@ -51,11 +81,9 @@ export default function Course() {
- - - - - + {courseData?.result.dateCourseList.map((course) => { + return ; + })}
diff --git a/src/pages/dateCourse/FindDateCourse.tsx b/src/pages/dateCourse/FindDateCourse.tsx index f2084c2..b10bd2e 100644 --- a/src/pages/dateCourse/FindDateCourse.tsx +++ b/src/pages/dateCourse/FindDateCourse.tsx @@ -1,16 +1,45 @@ -import { useState } from 'react'; +import { useEffect, useState } from 'react'; + +import type { TGetBookmarkedDateCourseResponse } from '@/types/dateCourse/dateCourse'; + +import useCourse from '@/hooks/course/useCourse'; import { MODAL_TYPES } from '@/components/common/modalProvider'; import Navigator from '@/components/common/navigator'; import DateCourse from '@/components/dateCourse/dateCourse'; import Filter from '@/assets/icons/filter_Blank.svg?react'; +import useFilterStore from '@/store/useFilterStore'; import useModalStore from '@/store/useModalStore'; function FindDateCourse() { const { openModal } = useModalStore(); const [current, setCurrent] = useState(1); + const [courseData, setCourseData] = useState(); + const { useGetBookmarkedCourse } = useCourse(); + const { budget, datePlaces, dateDurationTime, startTime, mealTypes, transportation, userPreferredKeywords } = useFilterStore(); + const { mutate: getBookmarkedDateCourse } = useGetBookmarkedCourse; + useEffect(() => { + getBookmarkedDateCourse( + { + page: current, + size: 5, + budget, + dateDurationTime, + datePlaces, + mealTypes, + transportation, + userPreferredKeywords, + startTime, + }, + { + onSuccess: (data) => { + setCourseData(data); + }, + }, + ); + }, [current]); return (
@@ -26,11 +55,9 @@ function FindDateCourse() {
- - - - - + {courseData?.result.dateCourseList.map((course) => { + return ; + })}
diff --git a/src/pages/dateCourse/MakeCourseResult.tsx b/src/pages/dateCourse/MakeCourseResult.tsx index 49edf0d..41d58d4 100644 --- a/src/pages/dateCourse/MakeCourseResult.tsx +++ b/src/pages/dateCourse/MakeCourseResult.tsx @@ -1,4 +1,9 @@ -import { useNavigate } from 'react-router-dom'; +import { useEffect, useState } from 'react'; +import { Navigate, useNavigate } from 'react-router-dom'; + +import type { TPostDateCourseResponse } from '@/types/dateCourse/dateCourse'; + +import useCourse from '@/hooks/course/useCourse'; import DateCourse from '@/components/dateCourse/dateCourse'; import DateCourseLoading from '@/components/dateCourse/dateCourseLoading'; @@ -7,13 +12,40 @@ import Button from '../../components/common/Button'; import Reload from '@/assets/icons/arrow_spin.svg?react'; import Logo from '@/assets/withTimeLogo//logo_Blank.svg?react'; +import useFilterStore from '@/store/useFilterStore'; export default function MakeCourseResult() { const navigate = useNavigate(); - const isLoading = false; - if (isLoading) { + const [courseData, setCourseData] = useState(); + const { useMakeCourse } = useCourse(); + const { budget, datePlaces, dateDurationTime, startTime, mealTypes, transportation, userPreferredKeywords } = useFilterStore(); + const { mutate: makeCourseMutate, isPending } = useMakeCourse; + + useEffect(() => { + makeCourseMutate( + { + budget: budget!, + dateDurationTime: dateDurationTime!, + datePlaces, + mealPlan: mealTypes, + transportation: transportation!, + userPreferredKeywords, + startTime: startTime!, + }, + { + onSuccess: (data) => { + setCourseData(data); + }, + }, + ); + }, []); + + if (isPending) { return ; } + if (!courseData) { + return ; + } return (
@@ -22,7 +54,7 @@ export default function MakeCourseResult() {
- +
diff --git a/src/store/useFilterStore.ts b/src/store/useFilterStore.ts new file mode 100644 index 0000000..952e9a0 --- /dev/null +++ b/src/store/useFilterStore.ts @@ -0,0 +1,37 @@ +import { create } from 'zustand'; +import { persist } from 'zustand/middleware'; + +export type TFilters = { + budget: string | null; + datePlaces: string[]; + mealTypes: string[]; + transportation: string | null; + userPreferredKeywords: string[]; + dateDurationTime: string | null; + startTime: string | null; +}; +type TActions = { + setField: (key: K, value: TFilters[K]) => void; + reset: () => void; +}; +const empty: TFilters = { + budget: null, + datePlaces: [], + mealTypes: [], + transportation: null, + userPreferredKeywords: [], + dateDurationTime: null, + startTime: null, +}; + +const useFilterStore = create()( + persist( + (set) => ({ + ...empty, + setField: (key, value) => set({ [key]: value } as any), + reset: () => set({ ...empty }), + }), + { name: 'date-course-filters' }, + ), +); +export default useFilterStore; diff --git a/src/types/dateCourse/dateCourse.ts b/src/types/dateCourse/dateCourse.ts index c53a426..a1bef47 100644 --- a/src/types/dateCourse/dateCourse.ts +++ b/src/types/dateCourse/dateCourse.ts @@ -54,6 +54,8 @@ export type TDateCourseSearchFilterOption = { subTitle?: string | null; type: 'choice' | 'search' | 'time' | 'choices' | 'keyword'; errorMessage: string | null; + apiRequestValue: string | string[] | null; + autoInit?: boolean; }; export interface IQuestion { @@ -62,6 +64,7 @@ export interface IQuestion { options: string[] | null; keyword: string | null; subTitle: string | null; + apiRequestValue: string[] | null; type: 'choice' | 'search' | 'time' | 'choices' | 'keyword'; } @@ -91,3 +94,84 @@ export type TRegion = { createdAt: string; updatedAt: string; }; + +export type TPostDateCourseRequest = { + budget: string; + datePlaces: string[]; + dateDurationTime: string; + mealPlan: string[]; + transportation: string; + userPreferredKeywords: string[]; + startTime: string; +}; + +export type TPostDateCourseResponse = TCommonResponse; + +export type TDatePlaces = { + name: string; + image: string; + tel: string; + averagePrive: number; + information: string; + latitude: number; + longitude: number; + roadNameAddress: string; + lotNumberAddress: string; + placeType: string; +}; +export type TDateCourse = { + dateCourseId: number; + name: string; + datePlaces: TDatePlaces[]; +}; +export type TPostBookmarkRequest = { + dateCourseId: number; +}; + +export type TPostBookmarkResponse = TCommonResponse<{ + dateCourseId: number; +}>; + +export type TDeleteBookmarkRequest = { + dateCourseId: number; +}; + +export type TDeleteBookmarkResponse = TCommonResponse<{ + dateCourseId: number; +}>; + +export type TGetDateCourseRequest = TCourseFilter & { + page: number; + size: number; +}; + +export type TGetDateCourseResponse = TCommonResponse<{ + dateCourseList: TDateCourse[]; + totalPages: number; + currentPage: number; + currentSize: number; + hasNextPage: boolean; +}>; + +export type TGetBookmarkedDateCourseRequest = TCourseFilter & { + page: number; + size: number; +}; + +export type TGetBookmarkedDateCourseResponse = TCommonResponse<{ + dateCourseList: TDateCourse[]; + totalPages: number; + currentPage: number; + currentSize: number; + hasNextPage: boolean; +}>; + +export type TCourseFilter = { + budget: string | null; + datePlaces: string[]; + dateDurationTime: string | null; + mealTypes: string[]; + transportation: string | null; + userPreferredKeywords: string[]; + startTime: string | null; +}; diff --git a/src/utils/dateCourseValidation.tsx b/src/utils/dateCourseValidation.tsx index 75a2a1a..fbfc86c 100644 --- a/src/utils/dateCourseValidation.tsx +++ b/src/utils/dateCourseValidation.tsx @@ -1,13 +1,19 @@ export const timeMap: Record = { - '1-2시간': 1.5, - '3-4시간': 3.5, - '반나절': 5.0, - '하루 종일': 8.0, + ONETOTWO: 1.5, + THREETOFOUR: 3.5, + HALFDAY: 5.0, + ALLDAY: 8.0, }; export const mealTimeRanges: Record = { - 아침: ['05:00', '10:00'], - 점심: ['10:30', '14:00'], - 저녁: ['17:30', '20:30'], + BREAKFAST: ['05:00', '10:00'], + LUNCH: ['10:30', '14:00'], + DINNER: ['17:30', '20:30'], +}; + +export const mealTimeKorean: Record = { + BREAKFAST: '아침', + LUNCH: '점심', + DINNER: '저녁', }; const keywordGroups: Record = { @@ -20,12 +26,12 @@ export const mealKeyword = ['양식', '한식', '중식', '이자카야/펍', ' export function MealTimeValidation({ meal, time, totalTime }: { meal: string[]; time: string; totalTime: string }): string | null { if (!time || meal.length === 0 || !totalTime) return null; + const timeStr = time.split('T')[1]; // 'HH:mm' const toMinutes = (t: string) => { const [h, m] = t.split(':').map(Number); return h * 60 + m; }; - const timeStr = time.split(' ')[1]; // 'HH:mm' const start = toMinutes(timeStr); // 데이트 시작 시간 const duration = timeMap[totalTime]; // 소요 시간(시간 단위) const end = start + duration * 60; // 종료 시간 (분) @@ -60,8 +66,10 @@ export function MealTimeValidation({ meal, time, totalTime }: { meal: string[]; // 아무것도 안겹치면 첫 번째 식사를 기준으로 안내 const first = meal[0]; + console.log(first); const [mealStartStr, mealEndStr] = mealTimeRanges[first]; - return `선택하신 시간에는 ${first} 식사를 하기 어려워요. (가능 시간: ${mealStartStr}~${mealEndStr})`; + + return `선택하신 시간에는 ${mealTimeKorean[first]} 식사를 하기 어려워요. (가능 시간: ${mealStartStr}~${mealEndStr})`; } type TDateTimeStartValidationInput = { @@ -71,11 +79,10 @@ type TDateTimeStartValidationInput = { export function DateTimeStartValidation({ totalTime, time }: TDateTimeStartValidationInput): string | null { if (!totalTime || !time) return null; - const duration = timeMap[totalTime]; if (duration == null) return null; + const timeStr = time.split('T')[1]; - const timeStr = time.split(' ')[1]; // 'HH:mm' const [startH, startM] = timeStr.split(':').map(Number); const startMinutes = startH * 60 + startM; @@ -91,11 +98,11 @@ export function DateTimeStartValidation({ totalTime, time }: TDateTimeStartValid export function TotalTimeMealValidation({ totalTime, meal }: { totalTime: string; meal: string[] | null }) { if (!meal) return null; - if (totalTime === '1-2시간') { + if (totalTime === 'ONETOTWO') { if (meal.length > 1) return `선택하신 시간에는 ${meal.length}가지 식사를 모두 포함하기 어려워요. 꼭 포함하고 싶은 식사만 선택해 주세요!`; - } else if (totalTime === '3-4시간') { + } else if (totalTime === 'THREETOFOUR') { if (meal.length > 1) return `선택하신 시간에는 ${meal.length}가지 식사를 모두 포함하기 어려워요. 꼭 포함하고 싶은 식사만 선택해 주세요!`; - } else if (totalTime === '반나절') { + } else if (totalTime === 'HALFDAY') { if (meal.length > 2) return `선택하신 시간에는 ${meal.length}가지 식사를 모두 포함하기 어려워요. 꼭 포함하고 싶은 식사만 선택해 주세요!`; } return null; @@ -124,9 +131,9 @@ export function KeywordGroupOverValidation({ keywords }: { keywords: string[] }) export function BudgetTimeValidation({ budget, totalTime }: { budget: string; totalTime: string }): string | null { const warningTable: Record = { - '3-4시간': ['1만원 이하'], - '반나절': ['1만원 이하', '1-2만원'], - '하루 종일': ['1만원 이하', '1-2만원', '2-3만원'], + THREETOFOUR: ['UNDER_10K'], + HALFDAY: ['UNDER_10K', 'FROM_10K_TO_20K'], + ALLDAY: ['UNDER_10K', 'FROM_10K_TO_20K', 'FROM_20K_TO_30K'], }; const warnings = warningTable[totalTime]; @@ -136,5 +143,3 @@ export function BudgetTimeValidation({ budget, totalTime }: { budget: string; to return null; } - -// 유효성 검사 9 -> 추후 API 나오면 제작 예정 From 1a273fcb7652950350516b2aa59706bac053fe0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=97=B0=EC=A7=84?= Date: Thu, 14 Aug 2025 03:05:01 +0900 Subject: [PATCH 02/17] =?UTF-8?q?feat:=20api=20=EC=9A=94=EC=B2=AD=20?= =?UTF-8?q?=EB=B0=A9=EC=8B=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/course/course.ts | 8 +--- .../modal/dateCourseSearchFilterModal.tsx | 42 +++++++--------- src/hooks/course/useCourse.ts | 10 ++-- src/hooks/course/useGetBookmarkedCourse.ts | 48 +++++++++++++++++++ src/hooks/course/useGetCourse.ts | 28 +++++++++++ src/pages/dateCourse/BookmarkedDateCourse.tsx | 46 +++++++----------- src/pages/dateCourse/CoursePage.tsx | 43 ++++++----------- src/pages/dateCourse/FindDateCourse.tsx | 41 ++++++---------- src/pages/dateCourse/MakeCourseResult.tsx | 2 +- src/queryKey/queryKey.ts | 27 +++++++++++ 10 files changed, 172 insertions(+), 123 deletions(-) create mode 100644 src/hooks/course/useGetBookmarkedCourse.ts create mode 100644 src/hooks/course/useGetCourse.ts diff --git a/src/api/course/course.ts b/src/api/course/course.ts index 19d3478..356a808 100644 --- a/src/api/course/course.ts +++ b/src/api/course/course.ts @@ -62,12 +62,10 @@ export const getDateCourse = async ({ page, size, }: TGetDateCourseRequest): Promise => { - const { data } = await axiosInstance.post('/api/v1/date-courses/search', { + const { data } = await axiosInstance.get('/api/v1/date-courses/search', { params: { page, size, - }, - data: { budget, datePlaces, mealTypes, @@ -87,12 +85,10 @@ export const getBookmarkedDateCourse = async ({ page, size, }: TGetBookmarkedDateCourseRequest): Promise => { - const { data } = await axiosInstance.post('/api/v1/date-courses/search', { + const { data } = await axiosInstance.get('/api/v1/date-courses/search', { params: { page, size, - }, - data: { budget, datePlaces, mealTypes, diff --git a/src/components/modal/dateCourseSearchFilterModal.tsx b/src/components/modal/dateCourseSearchFilterModal.tsx index 49597e5..69a4c60 100644 --- a/src/components/modal/dateCourseSearchFilterModal.tsx +++ b/src/components/modal/dateCourseSearchFilterModal.tsx @@ -1,5 +1,5 @@ // DateCourseSearchFilterModal.tsx -import { useEffect, useMemo, useState } from 'react'; +import { useMemo, useState } from 'react'; import { DateCourseQuestion } from '@/constants/dateCourseQuestion'; @@ -12,7 +12,7 @@ import { TotalTimeMealValidation, } from '@/utils/dateCourseValidation'; -import useCourse from '@/hooks/course/useCourse'; +import useGetCourse from '@/hooks/course/useGetCourse'; import Button from '../common/Button'; import Modal from '../common/modal'; @@ -25,9 +25,19 @@ type TProps = { onClose: () => void }; export default function DateCourseSearchFilterModal({ onClose }: TProps) { const { setField, ...filters } = useFilterStore(); const [errorMessages, setErrorMessages] = useState(Array(7).fill('')); - const { useGetBookmarkedCourse } = useCourse(); - const { mutate: getBookmarkedDateCourse } = useGetBookmarkedCourse; + const { budget, datePlaces, dateDurationTime, startTime, mealTypes, transportation, userPreferredKeywords } = useFilterStore(); + const { data } = useGetCourse({ + budget, + datePlaces, + dateDurationTime, + startTime, + mealTypes, + transportation, + userPreferredKeywords, + size: 5, + page: 1, + }); const Questions = useMemo( () => (Array.isArray(DateCourseQuestion) ? DateCourseQuestion.slice(0, 7) : []) @@ -101,27 +111,7 @@ export default function DateCourseSearchFilterModal({ onClose }: TProps) { apply(); runValidation(); }; - useEffect(() => { - getBookmarkedDateCourse( - { - page: 1, - size: 5, - budget: filters.budget, - dateDurationTime: filters.dateDurationTime, - datePlaces: filters.datePlaces, - mealTypes: filters.datePlaces, - transportation: filters.transportation, - userPreferredKeywords: filters.userPreferredKeywords, - startTime: filters.startTime, - }, - { - onSuccess: () => { - // 추후 데이터 추가되면 총 개수 불러와서 밑에 추가할 예정 - }, - }, - ); - }, [budget, datePlaces, dateDurationTime, mealTypes, transportation, userPreferredKeywords, startTime]); - + const number = 1234; return (
@@ -141,7 +131,7 @@ export default function DateCourseSearchFilterModal({ onClose }: TProps) {
diff --git a/src/hooks/course/useCourse.ts b/src/hooks/course/useCourse.ts index de640f0..b41ea9b 100644 --- a/src/hooks/course/useCourse.ts +++ b/src/hooks/course/useCourse.ts @@ -1,10 +1,8 @@ import { useCoreMutation } from '../customQuery'; -import { getBookmarkedDateCourse, getDateCourse, postDateCourse } from '@/api/course/course'; +import { postDateCourse } from '@/api/course/course'; -export default function useCourse() { +export const useCourse = () => { const useMakeCourse = useCoreMutation(postDateCourse); - const useGetCourse = useCoreMutation(getDateCourse); - const useGetBookmarkedCourse = useCoreMutation(getBookmarkedDateCourse); - return { useMakeCourse, useGetBookmarkedCourse, useGetCourse }; -} + return { useMakeCourse }; +}; diff --git a/src/hooks/course/useGetBookmarkedCourse.ts b/src/hooks/course/useGetBookmarkedCourse.ts new file mode 100644 index 0000000..8908f4b --- /dev/null +++ b/src/hooks/course/useGetBookmarkedCourse.ts @@ -0,0 +1,48 @@ +import type { TCourseFilter } from '@/types/dateCourse/dateCourse'; + +import { useCoreQuery } from '../customQuery'; + +import { getBookmarkedDateCourse } from '@/api/course/course'; +import { dateCourseKeys } from '@/queryKey/queryKey'; + +type TUseGetBookmarkedCourseProps = TCourseFilter & { + size: number; + page: number; +}; +export default function useGetBookmarkedCourse({ + budget, + datePlaces, + mealTypes, + dateDurationTime, + transportation, + userPreferredKeywords, + startTime, + size, + page, +}: TUseGetBookmarkedCourseProps) { + return useCoreQuery( + dateCourseKeys.getBookmarkedDateCourse({ + budget, + datePlaces, + mealTypes, + dateDurationTime, + transportation, + userPreferredKeywords, + startTime, + size, + page, + }).queryKey, + () => + getBookmarkedDateCourse({ + budget, + datePlaces, + mealTypes, + dateDurationTime, + transportation, + userPreferredKeywords, + startTime, + size, + page, + }), + ); +} diff --git a/src/hooks/course/useGetCourse.ts b/src/hooks/course/useGetCourse.ts new file mode 100644 index 0000000..5d5522c --- /dev/null +++ b/src/hooks/course/useGetCourse.ts @@ -0,0 +1,28 @@ +import type { TCourseFilter } from '@/types/dateCourse/dateCourse'; + +import { useCoreQuery } from '../customQuery'; + +import { getDateCourse } from '@/api/course/course'; +import { dateCourseKeys } from '@/queryKey/queryKey'; + +type TUseGetCourseProps = TCourseFilter & { + size: number; + page: number; +}; +export default function useGetCourse({ + budget, + datePlaces, + mealTypes, + dateDurationTime, + transportation, + userPreferredKeywords, + startTime, + size, + page, +}: TUseGetCourseProps) { + return useCoreQuery( + dateCourseKeys.getDateCourse({ budget, datePlaces, mealTypes, dateDurationTime, transportation, userPreferredKeywords, startTime, size, page }) + .queryKey, + () => getDateCourse({ budget, datePlaces, mealTypes, dateDurationTime, transportation, userPreferredKeywords, startTime, size, page }), + ); +} diff --git a/src/pages/dateCourse/BookmarkedDateCourse.tsx b/src/pages/dateCourse/BookmarkedDateCourse.tsx index 7250c26..7b86607 100644 --- a/src/pages/dateCourse/BookmarkedDateCourse.tsx +++ b/src/pages/dateCourse/BookmarkedDateCourse.tsx @@ -1,8 +1,6 @@ -import { useEffect, useState } from 'react'; +import { useState } from 'react'; -import type { TGetBookmarkedDateCourseResponse } from '@/types/dateCourse/dateCourse'; - -import useCourse from '@/hooks/course/useCourse'; +import useGetBookmarkedCourse from '@/hooks/course/useGetBookmarkedCourse'; import { MODAL_TYPES } from '@/components/common/modalProvider'; import Navigator from '@/components/common/navigator'; @@ -14,32 +12,22 @@ import useModalStore from '@/store/useModalStore'; function BookmarkedDateCourse() { const [current, setCurrent] = useState(1); - const [courseData, setCourseData] = useState(); const { openModal } = useModalStore(); - const { useGetBookmarkedCourse } = useCourse(); + const { budget, datePlaces, dateDurationTime, startTime, mealTypes, transportation, userPreferredKeywords } = useFilterStore(); - const { mutate: getBookmarkedDateCourse } = useGetBookmarkedCourse; - useEffect(() => { - getBookmarkedDateCourse( - { - page: current, - size: 5, - budget, - dateDurationTime, - datePlaces, - mealTypes, - transportation, - userPreferredKeywords, - startTime, - }, - { - onSuccess: (data) => { - setCourseData(data); - }, - }, - ); - }, [current]); + const { data } = useGetBookmarkedCourse({ + page: current, + size: 5, + budget, + dateDurationTime, + datePlaces, + mealTypes, + transportation, + userPreferredKeywords, + startTime, + }); + return (
@@ -55,11 +43,11 @@ function BookmarkedDateCourse() {
- {courseData?.result.dateCourseList.map((course) => { + {data?.result.dateCourseList.map((course) => { return ; })}
- +
diff --git a/src/pages/dateCourse/CoursePage.tsx b/src/pages/dateCourse/CoursePage.tsx index f9febfa..875206d 100644 --- a/src/pages/dateCourse/CoursePage.tsx +++ b/src/pages/dateCourse/CoursePage.tsx @@ -1,9 +1,7 @@ -import { useEffect, useState } from 'react'; +import { useState } from 'react'; import { useNavigate } from 'react-router-dom'; -import type { TGetBookmarkedDateCourseResponse } from '@/types/dateCourse/dateCourse'; - -import useCourse from '@/hooks/course/useCourse'; +import useGetBookmarkedCourse from '@/hooks/course/useGetBookmarkedCourse'; import { MODAL_TYPES } from '@/components/common/modalProvider'; import Navigator from '@/components/common/navigator'; @@ -18,31 +16,20 @@ export default function Course() { const navigate = useNavigate(); const { openModal } = useModalStore(); const [current, setCurrent] = useState(1); - const [courseData, setCourseData] = useState(); - const { useGetBookmarkedCourse } = useCourse(); const { budget, datePlaces, dateDurationTime, startTime, mealTypes, transportation, userPreferredKeywords } = useFilterStore(); - const { mutate: getBookmarkedDateCourse } = useGetBookmarkedCourse; - useEffect(() => { - getBookmarkedDateCourse( - { - page: current, - size: 5, - budget, - dateDurationTime, - datePlaces, - mealTypes, - transportation, - userPreferredKeywords, - startTime, - }, - { - onSuccess: (data) => { - setCourseData(data); - }, - }, - ); - }, [current]); + const { data } = useGetBookmarkedCourse({ + page: current, + size: 5, + budget, + dateDurationTime, + datePlaces, + mealTypes, + transportation, + userPreferredKeywords, + startTime, + }); + return (
@@ -81,7 +68,7 @@ export default function Course() {
- {courseData?.result.dateCourseList.map((course) => { + {data?.result.dateCourseList.map((course) => { return ; })}
diff --git a/src/pages/dateCourse/FindDateCourse.tsx b/src/pages/dateCourse/FindDateCourse.tsx index b10bd2e..801692a 100644 --- a/src/pages/dateCourse/FindDateCourse.tsx +++ b/src/pages/dateCourse/FindDateCourse.tsx @@ -1,8 +1,6 @@ -import { useEffect, useState } from 'react'; +import { useState } from 'react'; -import type { TGetBookmarkedDateCourseResponse } from '@/types/dateCourse/dateCourse'; - -import useCourse from '@/hooks/course/useCourse'; +import useGetBookmarkedCourse from '@/hooks/course/useGetBookmarkedCourse'; import { MODAL_TYPES } from '@/components/common/modalProvider'; import Navigator from '@/components/common/navigator'; @@ -15,31 +13,20 @@ import useModalStore from '@/store/useModalStore'; function FindDateCourse() { const { openModal } = useModalStore(); const [current, setCurrent] = useState(1); - const [courseData, setCourseData] = useState(); - const { useGetBookmarkedCourse } = useCourse(); const { budget, datePlaces, dateDurationTime, startTime, mealTypes, transportation, userPreferredKeywords } = useFilterStore(); - const { mutate: getBookmarkedDateCourse } = useGetBookmarkedCourse; - useEffect(() => { - getBookmarkedDateCourse( - { - page: current, - size: 5, - budget, - dateDurationTime, - datePlaces, - mealTypes, - transportation, - userPreferredKeywords, - startTime, - }, - { - onSuccess: (data) => { - setCourseData(data); - }, - }, - ); - }, [current]); + const { data: courseData } = useGetBookmarkedCourse({ + page: current, + size: 5, + budget, + dateDurationTime, + datePlaces, + mealTypes, + transportation, + userPreferredKeywords, + startTime, + }); + return (
diff --git a/src/pages/dateCourse/MakeCourseResult.tsx b/src/pages/dateCourse/MakeCourseResult.tsx index 41d58d4..c330da6 100644 --- a/src/pages/dateCourse/MakeCourseResult.tsx +++ b/src/pages/dateCourse/MakeCourseResult.tsx @@ -3,7 +3,7 @@ import { Navigate, useNavigate } from 'react-router-dom'; import type { TPostDateCourseResponse } from '@/types/dateCourse/dateCourse'; -import useCourse from '@/hooks/course/useCourse'; +import { useCourse } from '@/hooks/course/useCourse'; import DateCourse from '@/components/dateCourse/dateCourse'; import DateCourseLoading from '@/components/dateCourse/dateCourseLoading'; diff --git a/src/queryKey/queryKey.ts b/src/queryKey/queryKey.ts index 0b60752..b88fe19 100644 --- a/src/queryKey/queryKey.ts +++ b/src/queryKey/queryKey.ts @@ -24,3 +24,30 @@ export const NoticeKeys = createQueryKeys('notice', { all: () => ['notice'], getAllNotices: (page: number, size: number, noticeCategory: 'SERVICE' | 'SYSTEM') => ['notice', page, size, noticeCategory], }); + +export const dateCourseKeys = createQueryKeys('course', { + all: null, + getBookmarkedDateCourse: ({ budget, datePlaces, mealTypes, dateDurationTime, transportation, userPreferredKeywords, startTime, size, page }) => [ + 'bookmark', + budget, + datePlaces, + mealTypes, + dateDurationTime, + transportation, + userPreferredKeywords, + startTime, + size, + page, + ], + getDateCourse: ({ budget, datePlaces, mealTypes, dateDurationTime, transportation, userPreferredKeywords, startTime, size, page }) => [ + budget, + datePlaces, + mealTypes, + dateDurationTime, + transportation, + userPreferredKeywords, + startTime, + size, + page, + ], +}); From eab9c5b45d209ac6230dcf31f5353d1e428bd68c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=97=B0=EC=A7=84?= Date: Fri, 15 Aug 2025 05:40:40 +0900 Subject: [PATCH 03/17] =?UTF-8?q?feat:=20=EB=B0=B1=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + pnpm-lock.yaml | 6362 +++++++++++++++++ src/api/course/course.ts | 16 +- src/components/common/navigator.tsx | 28 +- src/components/dateCourse/dateCourse.tsx | 71 +- .../dateCourseSearchFilterOption.tsx | 14 +- src/components/dateCourse/dateKeyword.tsx | 4 +- src/components/dateCourse/infoElement.tsx | 2 +- src/components/dateCourse/timeline.tsx | 2 +- .../modal/dateCourseSearchFilterModal.tsx | 162 +- src/components/modal/deleteBookmarkModal.tsx | 23 +- src/constants/dateCourseQuestion.ts | 14 +- src/hooks/course/useBookmark.ts | 5 +- src/pages/dateCourse/BookmarkedDateCourse.tsx | 2 +- src/pages/dateCourse/FindDateCourse.tsx | 8 +- src/pages/dateCourse/MakeCourseResult.tsx | 25 +- src/pages/dateCourse/MakeCourseStep.tsx | 4 +- src/types/dateCourse/dateCourse.ts | 41 +- src/utils/dateCourseValidation.tsx | 1 - src/utils/timeZoneChange.ts | 24 + 20 files changed, 6663 insertions(+), 146 deletions(-) create mode 100644 pnpm-lock.yaml create mode 100644 src/utils/timeZoneChange.ts diff --git a/package.json b/package.json index 2c046f5..b0c2bc5 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "@tailwindcss/vite": "^4.1.7", "@types/lodash": "^4.17.20", "@types/lodash.throttle": "^4.1.9", + "@types/qs": "^6.14.0", "@types/react": "^19.1.2", "@types/react-dom": "^19.1.2", "@types/wordcloud": "^1.2.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..88d9031 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,6362 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@hookform/resolvers': + specifier: ^5.1.1 + version: 5.2.1(react-hook-form@7.62.0(react@19.1.1)) + '@lukemorales/query-key-factory': + specifier: ^1.3.4 + version: 1.3.4(@tanstack/query-core@5.83.1)(@tanstack/react-query@5.84.2(react@19.1.1)) + '@tanstack/react-query': + specifier: ^5.76.1 + version: 5.84.2(react@19.1.1) + '@tanstack/react-query-devtools': + specifier: ^5.76.1 + version: 5.84.2(@tanstack/react-query@5.84.2(react@19.1.1))(react@19.1.1) + add: + specifier: ^2.0.6 + version: 2.0.6 + axios: + specifier: ^1.9.0 + version: 1.11.0 + chart.js: + specifier: ^4.5.0 + version: 4.5.0 + chartjs-plugin-datalabels: + specifier: ^2.2.0 + version: 2.2.0(chart.js@4.5.0) + clsx: + specifier: ^2.1.1 + version: 2.1.1 + firebase: + specifier: ^12.0.0 + version: 12.1.0 + lodash: + specifier: ^4.17.21 + version: 4.17.21 + lodash.throttle: + specifier: ^4.1.1 + version: 4.1.1 + path: + specifier: ^0.12.7 + version: 0.12.7 + prettier: + specifier: ^3.5.3 + version: 3.6.2 + react: + specifier: ^19.1.0 + version: 19.1.1 + react-chartjs-2: + specifier: ^5.3.0 + version: 5.3.0(chart.js@4.5.0)(react@19.1.1) + react-dom: + specifier: ^19.1.0 + version: 19.1.1(react@19.1.1) + react-hook-form: + specifier: ^7.60.0 + version: 7.62.0(react@19.1.1) + react-intersection-observer: + specifier: ^9.16.0 + version: 9.16.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + react-router-dom: + specifier: ^7.6.0 + version: 7.8.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + react-spinners: + specifier: ^0.17.0 + version: 0.17.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + sonner: + specifier: ^2.0.3 + version: 2.0.7(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + tailwindcss: + specifier: ^4.1.7 + version: 4.1.11 + wordcloud: + specifier: ^1.2.3 + version: 1.2.3 + zod: + specifier: ^3.25.74 + version: 3.25.76 + zustand: + specifier: ^5.0.6 + version: 5.0.7(@types/react@19.1.9)(react@19.1.1) + devDependencies: + '@commitlint/cli': + specifier: ^19.8.1 + version: 19.8.1(@types/node@24.2.1)(typescript@5.8.3) + '@commitlint/config-conventional': + specifier: ^19.8.1 + version: 19.8.1 + '@eslint/js': + specifier: ^9.27.0 + version: 9.33.0 + '@tailwindcss/vite': + specifier: ^4.1.7 + version: 4.1.11(vite@7.1.1(@types/node@24.2.1)(jiti@2.5.1)(lightningcss@1.30.1)(yaml@2.8.1)) + '@types/lodash': + specifier: ^4.17.20 + version: 4.17.20 + '@types/lodash.throttle': + specifier: ^4.1.9 + version: 4.1.9 + '@types/qs': + specifier: ^6.14.0 + version: 6.14.0 + '@types/react': + specifier: ^19.1.2 + version: 19.1.9 + '@types/react-dom': + specifier: ^19.1.2 + version: 19.1.7(@types/react@19.1.9) + '@types/wordcloud': + specifier: ^1.2.2 + version: 1.2.2 + '@typescript-eslint/eslint-plugin': + specifier: ^8.32.1 + version: 8.39.0(@typescript-eslint/parser@8.39.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3) + '@typescript-eslint/parser': + specifier: ^8.32.1 + version: 8.39.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3) + '@vitejs/plugin-react-swc': + specifier: ^3.9.0 + version: 3.11.0(vite@7.1.1(@types/node@24.2.1)(jiti@2.5.1)(lightningcss@1.30.1)(yaml@2.8.1)) + autoprefixer: + specifier: ^10.4.21 + version: 10.4.21(postcss@8.5.6) + eslint: + specifier: ^9.27.0 + version: 9.33.0(jiti@2.5.1) + eslint-config-prettier: + specifier: ^10.1.5 + version: 10.1.8(eslint@9.33.0(jiti@2.5.1)) + eslint-plugin-import: + specifier: ^2.31.0 + version: 2.32.0(@typescript-eslint/parser@8.39.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint@9.33.0(jiti@2.5.1)) + eslint-plugin-import-name: + specifier: ^1.2.3 + version: 1.2.3 + eslint-plugin-jsx-a11y: + specifier: ^6.10.2 + version: 6.10.2(eslint@9.33.0(jiti@2.5.1)) + eslint-plugin-prettier: + specifier: ^5.4.0 + version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.5.1)))(eslint@9.33.0(jiti@2.5.1))(prettier@3.6.2) + eslint-plugin-react: + specifier: ^7.37.5 + version: 7.37.5(eslint@9.33.0(jiti@2.5.1)) + eslint-plugin-react-hooks: + specifier: ^5.2.0 + version: 5.2.0(eslint@9.33.0(jiti@2.5.1)) + eslint-plugin-react-refresh: + specifier: ^0.4.19 + version: 0.4.20(eslint@9.33.0(jiti@2.5.1)) + eslint-plugin-simple-import-sort: + specifier: ^12.1.1 + version: 12.1.1(eslint@9.33.0(jiti@2.5.1)) + globals: + specifier: ^16.0.0 + version: 16.3.0 + husky: + specifier: ^9.1.7 + version: 9.1.7 + lint-staged: + specifier: ^16.0.0 + version: 16.1.5 + typescript: + specifier: ~5.8.3 + version: 5.8.3 + typescript-eslint: + specifier: ^8.30.1 + version: 8.39.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3) + vite: + specifier: ^7.0.2 + version: 7.1.1(@types/node@24.2.1)(jiti@2.5.1)(lightningcss@1.30.1)(yaml@2.8.1) + vite-plugin-svgr: + specifier: ^4.3.0 + version: 4.3.0(rollup@4.46.2)(typescript@5.8.3)(vite@7.1.1(@types/node@24.2.1)(jiti@2.5.1)(lightningcss@1.30.1)(yaml@2.8.1)) + +packages: + + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + + '@babel/code-frame@7.27.1': + resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.28.0': + resolution: {integrity: sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.28.0': + resolution: {integrity: sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.28.0': + resolution: {integrity: sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.27.2': + resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.27.1': + resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.27.3': + resolution: {integrity: sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.27.1': + resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.27.1': + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.28.2': + resolution: {integrity: sha512-/V9771t+EgXz62aCcyofnQhGM8DQACbRhvzKFsXKC9QM+5MadF8ZmIm0crDMaz3+o0h0zXfJnd4EhbYbxsrcFw==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.28.0': + resolution: {integrity: sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/template@7.27.2': + resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.28.0': + resolution: {integrity: sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.28.2': + resolution: {integrity: sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==} + engines: {node: '>=6.9.0'} + + '@commitlint/cli@19.8.1': + resolution: {integrity: sha512-LXUdNIkspyxrlV6VDHWBmCZRtkEVRpBKxi2Gtw3J54cGWhLCTouVD/Q6ZSaSvd2YaDObWK8mDjrz3TIKtaQMAA==} + engines: {node: '>=v18'} + hasBin: true + + '@commitlint/config-conventional@19.8.1': + resolution: {integrity: sha512-/AZHJL6F6B/G959CsMAzrPKKZjeEiAVifRyEwXxcT6qtqbPwGw+iQxmNS+Bu+i09OCtdNRW6pNpBvgPrtMr9EQ==} + engines: {node: '>=v18'} + + '@commitlint/config-validator@19.8.1': + resolution: {integrity: sha512-0jvJ4u+eqGPBIzzSdqKNX1rvdbSU1lPNYlfQQRIFnBgLy26BtC0cFnr7c/AyuzExMxWsMOte6MkTi9I3SQ3iGQ==} + engines: {node: '>=v18'} + + '@commitlint/ensure@19.8.1': + resolution: {integrity: sha512-mXDnlJdvDzSObafjYrOSvZBwkD01cqB4gbnnFuVyNpGUM5ijwU/r/6uqUmBXAAOKRfyEjpkGVZxaDsCVnHAgyw==} + engines: {node: '>=v18'} + + '@commitlint/execute-rule@19.8.1': + resolution: {integrity: sha512-YfJyIqIKWI64Mgvn/sE7FXvVMQER/Cd+s3hZke6cI1xgNT/f6ZAz5heND0QtffH+KbcqAwXDEE1/5niYayYaQA==} + engines: {node: '>=v18'} + + '@commitlint/format@19.8.1': + resolution: {integrity: sha512-kSJj34Rp10ItP+Eh9oCItiuN/HwGQMXBnIRk69jdOwEW9llW9FlyqcWYbHPSGofmjsqeoxa38UaEA5tsbm2JWw==} + engines: {node: '>=v18'} + + '@commitlint/is-ignored@19.8.1': + resolution: {integrity: sha512-AceOhEhekBUQ5dzrVhDDsbMaY5LqtN8s1mqSnT2Kz1ERvVZkNihrs3Sfk1Je/rxRNbXYFzKZSHaPsEJJDJV8dg==} + engines: {node: '>=v18'} + + '@commitlint/lint@19.8.1': + resolution: {integrity: sha512-52PFbsl+1EvMuokZXLRlOsdcLHf10isTPlWwoY1FQIidTsTvjKXVXYb7AvtpWkDzRO2ZsqIgPK7bI98x8LRUEw==} + engines: {node: '>=v18'} + + '@commitlint/load@19.8.1': + resolution: {integrity: sha512-9V99EKG3u7z+FEoe4ikgq7YGRCSukAcvmKQuTtUyiYPnOd9a2/H9Ak1J9nJA1HChRQp9OA/sIKPugGS+FK/k1A==} + engines: {node: '>=v18'} + + '@commitlint/message@19.8.1': + resolution: {integrity: sha512-+PMLQvjRXiU+Ae0Wc+p99EoGEutzSXFVwQfa3jRNUZLNW5odZAyseb92OSBTKCu+9gGZiJASt76Cj3dLTtcTdg==} + engines: {node: '>=v18'} + + '@commitlint/parse@19.8.1': + resolution: {integrity: sha512-mmAHYcMBmAgJDKWdkjIGq50X4yB0pSGpxyOODwYmoexxxiUCy5JJT99t1+PEMK7KtsCtzuWYIAXYAiKR+k+/Jw==} + engines: {node: '>=v18'} + + '@commitlint/read@19.8.1': + resolution: {integrity: sha512-03Jbjb1MqluaVXKHKRuGhcKWtSgh3Jizqy2lJCRbRrnWpcM06MYm8th59Xcns8EqBYvo0Xqb+2DoZFlga97uXQ==} + engines: {node: '>=v18'} + + '@commitlint/resolve-extends@19.8.1': + resolution: {integrity: sha512-GM0mAhFk49I+T/5UCYns5ayGStkTt4XFFrjjf0L4S26xoMTSkdCf9ZRO8en1kuopC4isDFuEm7ZOm/WRVeElVg==} + engines: {node: '>=v18'} + + '@commitlint/rules@19.8.1': + resolution: {integrity: sha512-Hnlhd9DyvGiGwjfjfToMi1dsnw1EXKGJNLTcsuGORHz6SS9swRgkBsou33MQ2n51/boIDrbsg4tIBbRpEWK2kw==} + engines: {node: '>=v18'} + + '@commitlint/to-lines@19.8.1': + resolution: {integrity: sha512-98Mm5inzbWTKuZQr2aW4SReY6WUukdWXuZhrqf1QdKPZBCCsXuG87c+iP0bwtD6DBnmVVQjgp4whoHRVixyPBg==} + engines: {node: '>=v18'} + + '@commitlint/top-level@19.8.1': + resolution: {integrity: sha512-Ph8IN1IOHPSDhURCSXBz44+CIu+60duFwRsg6HqaISFHQHbmBtxVw4ZrFNIYUzEP7WwrNPxa2/5qJ//NK1FGcw==} + engines: {node: '>=v18'} + + '@commitlint/types@19.8.1': + resolution: {integrity: sha512-/yCrWGCoA1SVKOks25EGadP9Pnj0oAIHGpl2wH2M2Y46dPM2ueb8wyCVOD7O3WCTkaJ0IkKvzhl1JY7+uCT2Dw==} + engines: {node: '>=v18'} + + '@esbuild/aix-ppc64@0.25.8': + resolution: {integrity: sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.25.8': + resolution: {integrity: sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.25.8': + resolution: {integrity: sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.25.8': + resolution: {integrity: sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.25.8': + resolution: {integrity: sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.8': + resolution: {integrity: sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.25.8': + resolution: {integrity: sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.8': + resolution: {integrity: sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.25.8': + resolution: {integrity: sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.25.8': + resolution: {integrity: sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.25.8': + resolution: {integrity: sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.25.8': + resolution: {integrity: sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.25.8': + resolution: {integrity: sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.25.8': + resolution: {integrity: sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.8': + resolution: {integrity: sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.25.8': + resolution: {integrity: sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.25.8': + resolution: {integrity: sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.25.8': + resolution: {integrity: sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.8': + resolution: {integrity: sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.25.8': + resolution: {integrity: sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.25.8': + resolution: {integrity: sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.25.8': + resolution: {integrity: sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.25.8': + resolution: {integrity: sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.25.8': + resolution: {integrity: sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.25.8': + resolution: {integrity: sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.25.8': + resolution: {integrity: sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@eslint-community/eslint-utils@4.7.0': + resolution: {integrity: sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.1': + resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/config-array@0.21.0': + resolution: {integrity: sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/config-helpers@0.3.1': + resolution: {integrity: sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.15.2': + resolution: {integrity: sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/eslintrc@3.3.1': + resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.33.0': + resolution: {integrity: sha512-5K1/mKhWaMfreBGJTwval43JJmkip0RmM+3+IuqupeSKNC/Th2Kc7ucaq5ovTSra/OOKB9c58CGSz3QMVbWt0A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.6': + resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.3.5': + resolution: {integrity: sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@firebase/ai@2.1.0': + resolution: {integrity: sha512-4HvFr4YIzNFh0MowJLahOjJDezYSTjQar0XYVu/sAycoxQ+kBsfXuTPRLVXCYfMR5oNwQgYe4Q2gAOYKKqsOyA==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app': 0.x + '@firebase/app-types': 0.x + + '@firebase/analytics-compat@0.2.24': + resolution: {integrity: sha512-jE+kJnPG86XSqGQGhXXYt1tpTbCTED8OQJ/PQ90SEw14CuxRxx/H+lFbWA1rlFtFSsTCptAJtgyRBwr/f00vsw==} + peerDependencies: + '@firebase/app-compat': 0.x + + '@firebase/analytics-types@0.8.3': + resolution: {integrity: sha512-VrIp/d8iq2g501qO46uGz3hjbDb8xzYMrbu8Tp0ovzIzrvJZ2fvmj649gTjge/b7cCCcjT0H37g1gVtlNhnkbg==} + + '@firebase/analytics@0.10.18': + resolution: {integrity: sha512-iN7IgLvM06iFk8BeFoWqvVpRFW3Z70f+Qe2PfCJ7vPIgLPjHXDE774DhCT5Y2/ZU/ZbXPDPD60x/XPWEoZLNdg==} + peerDependencies: + '@firebase/app': 0.x + + '@firebase/app-check-compat@0.4.0': + resolution: {integrity: sha512-UfK2Q8RJNjYM/8MFORltZRG9lJj11k0nW84rrffiKvcJxLf1jf6IEjCIkCamykHE73C6BwqhVfhIBs69GXQV0g==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app-compat': 0.x + + '@firebase/app-check-interop-types@0.3.3': + resolution: {integrity: sha512-gAlxfPLT2j8bTI/qfe3ahl2I2YcBQ8cFIBdhAQA4I2f3TndcO+22YizyGYuttLHPQEpWkhmpFW60VCFEPg4g5A==} + + '@firebase/app-check-types@0.5.3': + resolution: {integrity: sha512-hyl5rKSj0QmwPdsAxrI5x1otDlByQ7bvNvVt8G/XPO2CSwE++rmSVf3VEhaeOR4J8ZFaF0Z0NDSmLejPweZ3ng==} + + '@firebase/app-check@0.11.0': + resolution: {integrity: sha512-XAvALQayUMBJo58U/rxW02IhsesaxxfWVmVkauZvGEz3vOAjMEQnzFlyblqkc2iAaO82uJ2ZVyZv9XzPfxjJ6w==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app': 0.x + + '@firebase/app-compat@0.5.1': + resolution: {integrity: sha512-BEy1L6Ufd85ZSP79HDIv0//T9p7d5Bepwy+2mKYkgdXBGKTbFm2e2KxyF1nq4zSQ6RRBxWi0IY0zFVmoBTZlUA==} + engines: {node: '>=20.0.0'} + + '@firebase/app-types@0.9.3': + resolution: {integrity: sha512-kRVpIl4vVGJ4baogMDINbyrIOtOxqhkZQg4jTq3l8Lw6WSk0xfpEYzezFu+Kl4ve4fbPl79dvwRtaFqAC/ucCw==} + + '@firebase/app@0.14.1': + resolution: {integrity: sha512-jxTrDbxnGoX7cGz7aP9E7v9iKvBbQfZ8Gz4TH3SfrrkcyIojJM3+hJnlbGnGxHrABts844AxRcg00arMZEyA6Q==} + engines: {node: '>=20.0.0'} + + '@firebase/auth-compat@0.6.0': + resolution: {integrity: sha512-J0lGSxXlG/lYVi45wbpPhcWiWUMXevY4fvLZsN1GHh+po7TZVng+figdHBVhFheaiipU8HZyc7ljw1jNojM2nw==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app-compat': 0.x + + '@firebase/auth-interop-types@0.2.4': + resolution: {integrity: sha512-JPgcXKCuO+CWqGDnigBtvo09HeBs5u/Ktc2GaFj2m01hLarbxthLNm7Fk8iOP1aqAtXV+fnnGj7U28xmk7IwVA==} + + '@firebase/auth-types@0.13.0': + resolution: {integrity: sha512-S/PuIjni0AQRLF+l9ck0YpsMOdE8GO2KU6ubmBB7P+7TJUCQDa3R1dlgYm9UzGbbePMZsp0xzB93f2b/CgxMOg==} + peerDependencies: + '@firebase/app-types': 0.x + '@firebase/util': 1.x + + '@firebase/auth@1.11.0': + resolution: {integrity: sha512-5j7+ua93X+IRcJ1oMDTClTo85l7Xe40WSkoJ+shzPrX7OISlVWLdE1mKC57PSD+/LfAbdhJmvKixINBw2ESK6w==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app': 0.x + '@react-native-async-storage/async-storage': ^1.18.1 + peerDependenciesMeta: + '@react-native-async-storage/async-storage': + optional: true + + '@firebase/component@0.7.0': + resolution: {integrity: sha512-wR9En2A+WESUHexjmRHkqtaVH94WLNKt6rmeqZhSLBybg4Wyf0Umk04SZsS6sBq4102ZsDBFwoqMqJYj2IoDSg==} + engines: {node: '>=20.0.0'} + + '@firebase/data-connect@0.3.11': + resolution: {integrity: sha512-G258eLzAD6im9Bsw+Qm1Z+P4x0PGNQ45yeUuuqe5M9B1rn0RJvvsQCRHXgE52Z+n9+WX1OJd/crcuunvOGc7Vw==} + peerDependencies: + '@firebase/app': 0.x + + '@firebase/database-compat@2.1.0': + resolution: {integrity: sha512-8nYc43RqxScsePVd1qe1xxvWNf0OBnbwHxmXJ7MHSuuTVYFO3eLyLW3PiCKJ9fHnmIz4p4LbieXwz+qtr9PZDg==} + engines: {node: '>=20.0.0'} + + '@firebase/database-types@1.0.16': + resolution: {integrity: sha512-xkQLQfU5De7+SPhEGAXFBnDryUWhhlFXelEg2YeZOQMCdoe7dL64DDAd77SQsR+6uoXIZY5MB4y/inCs4GTfcw==} + + '@firebase/database@1.1.0': + resolution: {integrity: sha512-gM6MJFae3pTyNLoc9VcJNuaUDej0ctdjn3cVtILo3D5lpp0dmUHHLFN/pUKe7ImyeB1KAvRlEYxvIHNF04Filg==} + engines: {node: '>=20.0.0'} + + '@firebase/firestore-compat@0.4.0': + resolution: {integrity: sha512-4O7v4VFeSEwAZtLjsaj33YrMHMRjplOIYC2CiYsF6o/MboOhrhe01VrTt8iY9Y5EwjRHuRz4pS6jMBT8LfQYJA==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app-compat': 0.x + + '@firebase/firestore-types@3.0.3': + resolution: {integrity: sha512-hD2jGdiWRxB/eZWF89xcK9gF8wvENDJkzpVFb4aGkzfEaKxVRD1kjz1t1Wj8VZEp2LCB53Yx1zD8mrhQu87R6Q==} + peerDependencies: + '@firebase/app-types': 0.x + '@firebase/util': 1.x + + '@firebase/firestore@4.9.0': + resolution: {integrity: sha512-5zl0+/h1GvlCSLt06RMwqFsd7uqRtnNZt4sW99k2rKRd6k/ECObIWlEnvthm2cuOSnUmwZknFqtmd1qyYSLUuQ==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app': 0.x + + '@firebase/functions-compat@0.4.0': + resolution: {integrity: sha512-VPgtvoGFywWbQqtvgJnVWIDFSHV1WE6Hmyi5EGI+P+56EskiGkmnw6lEqc/MEUfGpPGdvmc4I9XMU81uj766/g==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app-compat': 0.x + + '@firebase/functions-types@0.6.3': + resolution: {integrity: sha512-EZoDKQLUHFKNx6VLipQwrSMh01A1SaL3Wg6Hpi//x6/fJ6Ee4hrAeswK99I5Ht8roiniKHw4iO0B1Oxj5I4plg==} + + '@firebase/functions@0.13.0': + resolution: {integrity: sha512-2/LH5xIbD8aaLOWSFHAwwAybgSzHIM0dB5oVOL0zZnxFG1LctX2bc1NIAaPk1T+Zo9aVkLKUlB5fTXTkVUQprQ==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app': 0.x + + '@firebase/installations-compat@0.2.19': + resolution: {integrity: sha512-khfzIY3EI5LePePo7vT19/VEIH1E3iYsHknI/6ek9T8QCozAZshWT9CjlwOzZrKvTHMeNcbpo/VSOSIWDSjWdQ==} + peerDependencies: + '@firebase/app-compat': 0.x + + '@firebase/installations-types@0.5.3': + resolution: {integrity: sha512-2FJI7gkLqIE0iYsNQ1P751lO3hER+Umykel+TkLwHj6plzWVxqvfclPUZhcKFVQObqloEBTmpi2Ozn7EkCABAA==} + peerDependencies: + '@firebase/app-types': 0.x + + '@firebase/installations@0.6.19': + resolution: {integrity: sha512-nGDmiwKLI1lerhwfwSHvMR9RZuIH5/8E3kgUWnVRqqL7kGVSktjLTWEMva7oh5yxQ3zXfIlIwJwMcaM5bK5j8Q==} + peerDependencies: + '@firebase/app': 0.x + + '@firebase/logger@0.5.0': + resolution: {integrity: sha512-cGskaAvkrnh42b3BA3doDWeBmuHFO/Mx5A83rbRDYakPjO9bJtRL3dX7javzc2Rr/JHZf4HlterTW2lUkfeN4g==} + engines: {node: '>=20.0.0'} + + '@firebase/messaging-compat@0.2.23': + resolution: {integrity: sha512-SN857v/kBUvlQ9X/UjAqBoQ2FEaL1ZozpnmL1ByTe57iXkmnVVFm9KqAsTfmf+OEwWI4kJJe9NObtN/w22lUgg==} + peerDependencies: + '@firebase/app-compat': 0.x + + '@firebase/messaging-interop-types@0.2.3': + resolution: {integrity: sha512-xfzFaJpzcmtDjycpDeCUj0Ge10ATFi/VHVIvEEjDNc3hodVBQADZ7BWQU7CuFpjSHE+eLuBI13z5F/9xOoGX8Q==} + + '@firebase/messaging@0.12.23': + resolution: {integrity: sha512-cfuzv47XxqW4HH/OcR5rM+AlQd1xL/VhuaeW/wzMW1LFrsFcTn0GND/hak1vkQc2th8UisBcrkVcQAnOnKwYxg==} + peerDependencies: + '@firebase/app': 0.x + + '@firebase/performance-compat@0.2.22': + resolution: {integrity: sha512-xLKxaSAl/FVi10wDX/CHIYEUP13jXUjinL+UaNXT9ByIvxII5Ne5150mx6IgM8G6Q3V+sPiw9C8/kygkyHUVxg==} + peerDependencies: + '@firebase/app-compat': 0.x + + '@firebase/performance-types@0.2.3': + resolution: {integrity: sha512-IgkyTz6QZVPAq8GSkLYJvwSLr3LS9+V6vNPQr0x4YozZJiLF5jYixj0amDtATf1X0EtYHqoPO48a9ija8GocxQ==} + + '@firebase/performance@0.7.9': + resolution: {integrity: sha512-UzybENl1EdM2I1sjYm74xGt/0JzRnU/0VmfMAKo2LSpHJzaj77FCLZXmYQ4oOuE+Pxtt8Wy2BVJEENiZkaZAzQ==} + peerDependencies: + '@firebase/app': 0.x + + '@firebase/remote-config-compat@0.2.19': + resolution: {integrity: sha512-y7PZAb0l5+5oIgLJr88TNSelxuASGlXyAKj+3pUc4fDuRIdPNBoONMHaIUa9rlffBR5dErmaD2wUBJ7Z1a513Q==} + peerDependencies: + '@firebase/app-compat': 0.x + + '@firebase/remote-config-types@0.4.0': + resolution: {integrity: sha512-7p3mRE/ldCNYt8fmWMQ/MSGRmXYlJ15Rvs9Rk17t8p0WwZDbeK7eRmoI1tvCPaDzn9Oqh+yD6Lw+sGLsLg4kKg==} + + '@firebase/remote-config@0.6.6': + resolution: {integrity: sha512-Yelp5xd8hM4NO1G1SuWrIk4h5K42mNwC98eWZ9YLVu6Z0S6hFk1mxotAdCRmH2luH8FASlYgLLq6OQLZ4nbnCA==} + peerDependencies: + '@firebase/app': 0.x + + '@firebase/storage-compat@0.4.0': + resolution: {integrity: sha512-vDzhgGczr1OfcOy285YAPur5pWDEvD67w4thyeCUh6Ys0izN9fNYtA1MJERmNBfqjqu0lg0FM5GLbw0Il21M+g==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app-compat': 0.x + + '@firebase/storage-types@0.8.3': + resolution: {integrity: sha512-+Muk7g9uwngTpd8xn9OdF/D48uiQ7I1Fae7ULsWPuKoCH3HU7bfFPhxtJYzyhjdniowhuDpQcfPmuNRAqZEfvg==} + peerDependencies: + '@firebase/app-types': 0.x + '@firebase/util': 1.x + + '@firebase/storage@0.14.0': + resolution: {integrity: sha512-xWWbb15o6/pWEw8H01UQ1dC5U3rf8QTAzOChYyCpafV6Xki7KVp3Yaw2nSklUwHEziSWE9KoZJS7iYeyqWnYFA==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app': 0.x + + '@firebase/util@1.13.0': + resolution: {integrity: sha512-0AZUyYUfpMNcztR5l09izHwXkZpghLgCUaAGjtMwXnCg3bj4ml5VgiwqOMOxJ+Nw4qN/zJAaOQBcJ7KGkWStqQ==} + engines: {node: '>=20.0.0'} + + '@firebase/webchannel-wrapper@1.0.4': + resolution: {integrity: sha512-6m8+P+dE/RPl4OPzjTxcTbQ0rGeRyeTvAi9KwIffBVCiAMKrfXfLZaqD1F+m8t4B5/Q5aHsMozOgirkH1F5oMQ==} + + '@grpc/grpc-js@1.9.15': + resolution: {integrity: sha512-nqE7Hc0AzI+euzUwDAy0aY5hCp10r734gMGRdU+qOPX0XSceI2ULrcXB5U2xSc5VkWwalCj4M7GzCAygZl2KoQ==} + engines: {node: ^8.13.0 || >=10.10.0} + + '@grpc/proto-loader@0.7.15': + resolution: {integrity: sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ==} + engines: {node: '>=6'} + hasBin: true + + '@hookform/resolvers@5.2.1': + resolution: {integrity: sha512-u0+6X58gkjMcxur1wRWokA7XsiiBJ6aK17aPZxhkoYiK5J+HcTx0Vhu9ovXe6H+dVpO6cjrn2FkJTryXEMlryQ==} + peerDependencies: + react-hook-form: ^7.55.0 + + '@humanfs/core@0.19.1': + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.6': + resolution: {integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.3.1': + resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==} + engines: {node: '>=18.18'} + + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} + + '@isaacs/fs-minipass@4.0.1': + resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} + engines: {node: '>=18.0.0'} + + '@jridgewell/gen-mapping@0.3.12': + resolution: {integrity: sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.4': + resolution: {integrity: sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==} + + '@jridgewell/trace-mapping@0.3.29': + resolution: {integrity: sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==} + + '@kurkle/color@0.3.4': + resolution: {integrity: sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==} + + '@lukemorales/query-key-factory@1.3.4': + resolution: {integrity: sha512-A3frRDdkmaNNQi6mxIshsDk4chRXWoXa05US8fBo4kci/H+lVmujS6QrwQLLGIkNIRFGjMqp2uKjC4XsLdydRw==} + engines: {node: '>=14'} + peerDependencies: + '@tanstack/query-core': '>= 4.0.0' + '@tanstack/react-query': '>= 4.0.0' + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@pkgr/core@0.2.9': + resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + + '@protobufjs/aspromise@1.1.2': + resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} + + '@protobufjs/base64@1.1.2': + resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} + + '@protobufjs/codegen@2.0.4': + resolution: {integrity: sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==} + + '@protobufjs/eventemitter@1.1.0': + resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==} + + '@protobufjs/fetch@1.1.0': + resolution: {integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==} + + '@protobufjs/float@1.0.2': + resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} + + '@protobufjs/inquire@1.1.0': + resolution: {integrity: sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==} + + '@protobufjs/path@1.1.2': + resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} + + '@protobufjs/pool@1.1.0': + resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} + + '@protobufjs/utf8@1.1.0': + resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} + + '@rolldown/pluginutils@1.0.0-beta.27': + resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} + + '@rollup/pluginutils@5.2.0': + resolution: {integrity: sha512-qWJ2ZTbmumwiLFomfzTyt5Kng4hwPi9rwCYN4SHb6eaRU1KNO4ccxINHr/VhH4GgPlt1XfSTLX2LBTme8ne4Zw==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/rollup-android-arm-eabi@4.46.2': + resolution: {integrity: sha512-Zj3Hl6sN34xJtMv7Anwb5Gu01yujyE/cLBDB2gnHTAHaWS1Z38L7kuSG+oAh0giZMqG060f/YBStXtMH6FvPMA==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.46.2': + resolution: {integrity: sha512-nTeCWY83kN64oQ5MGz3CgtPx8NSOhC5lWtsjTs+8JAJNLcP3QbLCtDDgUKQc/Ro/frpMq4SHUaHN6AMltcEoLQ==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.46.2': + resolution: {integrity: sha512-HV7bW2Fb/F5KPdM/9bApunQh68YVDU8sO8BvcW9OngQVN3HHHkw99wFupuUJfGR9pYLLAjcAOA6iO+evsbBaPQ==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.46.2': + resolution: {integrity: sha512-SSj8TlYV5nJixSsm/y3QXfhspSiLYP11zpfwp6G/YDXctf3Xkdnk4woJIF5VQe0of2OjzTt8EsxnJDCdHd2xMA==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.46.2': + resolution: {integrity: sha512-ZyrsG4TIT9xnOlLsSSi9w/X29tCbK1yegE49RYm3tu3wF1L/B6LVMqnEWyDB26d9Ecx9zrmXCiPmIabVuLmNSg==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.46.2': + resolution: {integrity: sha512-pCgHFoOECwVCJ5GFq8+gR8SBKnMO+xe5UEqbemxBpCKYQddRQMgomv1104RnLSg7nNvgKy05sLsY51+OVRyiVw==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.46.2': + resolution: {integrity: sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.46.2': + resolution: {integrity: sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.46.2': + resolution: {integrity: sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.46.2': + resolution: {integrity: sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loongarch64-gnu@4.46.2': + resolution: {integrity: sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.46.2': + resolution: {integrity: sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.46.2': + resolution: {integrity: sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.46.2': + resolution: {integrity: sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.46.2': + resolution: {integrity: sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.46.2': + resolution: {integrity: sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.46.2': + resolution: {integrity: sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-win32-arm64-msvc@4.46.2': + resolution: {integrity: sha512-wiJWMIpeaak/jsbaq2HMh/rzZxHVW1rU6coyeNNpMwk5isiPjSTx0a4YLSlYDwBH/WBvLz+EtsNqQScZTLJy3g==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.46.2': + resolution: {integrity: sha512-gBgaUDESVzMgWZhcyjfs9QFK16D8K6QZpwAaVNJxYDLHWayOta4ZMjGm/vsAEy3hvlS2GosVFlBlP9/Wb85DqQ==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.46.2': + resolution: {integrity: sha512-CvUo2ixeIQGtF6WvuB87XWqPQkoFAFqW+HUo/WzHwuHDvIwZCtjdWXoYCcr06iKGydiqTclC4jU/TNObC/xKZg==} + cpu: [x64] + os: [win32] + + '@rtsao/scc@1.1.0': + resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + + '@standard-schema/utils@0.3.0': + resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==} + + '@svgr/babel-plugin-add-jsx-attribute@8.0.0': + resolution: {integrity: sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-remove-jsx-attribute@8.0.0': + resolution: {integrity: sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0': + resolution: {integrity: sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0': + resolution: {integrity: sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-svg-dynamic-title@8.0.0': + resolution: {integrity: sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-svg-em-dimensions@8.0.0': + resolution: {integrity: sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-transform-react-native-svg@8.1.0': + resolution: {integrity: sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-plugin-transform-svg-component@8.0.0': + resolution: {integrity: sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==} + engines: {node: '>=12'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/babel-preset@8.1.0': + resolution: {integrity: sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@svgr/core@8.1.0': + resolution: {integrity: sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==} + engines: {node: '>=14'} + + '@svgr/hast-util-to-babel-ast@8.0.0': + resolution: {integrity: sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==} + engines: {node: '>=14'} + + '@svgr/plugin-jsx@8.1.0': + resolution: {integrity: sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==} + engines: {node: '>=14'} + peerDependencies: + '@svgr/core': '*' + + '@swc/core-darwin-arm64@1.13.3': + resolution: {integrity: sha512-ux0Ws4pSpBTqbDS9GlVP354MekB1DwYlbxXU3VhnDr4GBcCOimpocx62x7cFJkSpEBF8bmX8+/TTCGKh4PbyXw==} + engines: {node: '>=10'} + cpu: [arm64] + os: [darwin] + + '@swc/core-darwin-x64@1.13.3': + resolution: {integrity: sha512-p0X6yhxmNUOMZrbeZ3ZNsPige8lSlSe1llllXvpCLkKKxN/k5vZt1sULoq6Nj4eQ7KeHQVm81/+AwKZyf/e0TA==} + engines: {node: '>=10'} + cpu: [x64] + os: [darwin] + + '@swc/core-linux-arm-gnueabihf@1.13.3': + resolution: {integrity: sha512-OmDoiexL2fVWvQTCtoh0xHMyEkZweQAlh4dRyvl8ugqIPEVARSYtaj55TBMUJIP44mSUOJ5tytjzhn2KFxFcBA==} + engines: {node: '>=10'} + cpu: [arm] + os: [linux] + + '@swc/core-linux-arm64-gnu@1.13.3': + resolution: {integrity: sha512-STfKku3QfnuUj6k3g9ld4vwhtgCGYIFQmsGPPgT9MK/dI3Lwnpe5Gs5t1inoUIoGNP8sIOLlBB4HV4MmBjQuhw==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + + '@swc/core-linux-arm64-musl@1.13.3': + resolution: {integrity: sha512-bc+CXYlFc1t8pv9yZJGus372ldzOVscBl7encUBlU1m/Sig0+NDJLz6cXXRcFyl6ABNOApWeR4Yl7iUWx6C8og==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + + '@swc/core-linux-x64-gnu@1.13.3': + resolution: {integrity: sha512-dFXoa0TEhohrKcxn/54YKs1iwNeW6tUkHJgXW33H381SvjKFUV53WR231jh1sWVJETjA3vsAwxKwR23s7UCmUA==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + + '@swc/core-linux-x64-musl@1.13.3': + resolution: {integrity: sha512-ieyjisLB+ldexiE/yD8uomaZuZIbTc8tjquYln9Quh5ykOBY7LpJJYBWvWtm1g3pHv6AXlBI8Jay7Fffb6aLfA==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + + '@swc/core-win32-arm64-msvc@1.13.3': + resolution: {integrity: sha512-elTQpnaX5vESSbhCEgcwXjpMsnUbqqHfEpB7ewpkAsLzKEXZaK67ihSRYAuAx6ewRQTo7DS5iTT6X5aQD3MzMw==} + engines: {node: '>=10'} + cpu: [arm64] + os: [win32] + + '@swc/core-win32-ia32-msvc@1.13.3': + resolution: {integrity: sha512-nvehQVEOdI1BleJpuUgPLrclJ0TzbEMc+MarXDmmiRFwEUGqj+pnfkTSb7RZyS1puU74IXdK/YhTirHurtbI9w==} + engines: {node: '>=10'} + cpu: [ia32] + os: [win32] + + '@swc/core-win32-x64-msvc@1.13.3': + resolution: {integrity: sha512-A+JSKGkRbPLVV2Kwx8TaDAV0yXIXm/gc8m98hSkVDGlPBBmydgzNdWy3X7HTUBM7IDk7YlWE7w2+RUGjdgpTmg==} + engines: {node: '>=10'} + cpu: [x64] + os: [win32] + + '@swc/core@1.13.3': + resolution: {integrity: sha512-ZaDETVWnm6FE0fc+c2UE8MHYVS3Fe91o5vkmGfgwGXFbxYvAjKSqxM/j4cRc9T7VZNSJjriXq58XkfCp3Y6f+w==} + engines: {node: '>=10'} + peerDependencies: + '@swc/helpers': '>=0.5.17' + peerDependenciesMeta: + '@swc/helpers': + optional: true + + '@swc/counter@0.1.3': + resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} + + '@swc/types@0.1.24': + resolution: {integrity: sha512-tjTMh3V4vAORHtdTprLlfoMptu1WfTZG9Rsca6yOKyNYsRr+MUXutKmliB17orgSZk5DpnDxs8GUdd/qwYxOng==} + + '@tailwindcss/node@4.1.11': + resolution: {integrity: sha512-yzhzuGRmv5QyU9qLNg4GTlYI6STedBWRE7NjxP45CsFYYq9taI0zJXZBMqIC/c8fViNLhmrbpSFS57EoxUmD6Q==} + + '@tailwindcss/oxide-android-arm64@4.1.11': + resolution: {integrity: sha512-3IfFuATVRUMZZprEIx9OGDjG3Ou3jG4xQzNTvjDoKmU9JdmoCohQJ83MYd0GPnQIu89YoJqvMM0G3uqLRFtetg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.1.11': + resolution: {integrity: sha512-ESgStEOEsyg8J5YcMb1xl8WFOXfeBmrhAwGsFxxB2CxY9evy63+AtpbDLAyRkJnxLy2WsD1qF13E97uQyP1lfQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.1.11': + resolution: {integrity: sha512-EgnK8kRchgmgzG6jE10UQNaH9Mwi2n+yw1jWmof9Vyg2lpKNX2ioe7CJdf9M5f8V9uaQxInenZkOxnTVL3fhAw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.1.11': + resolution: {integrity: sha512-xdqKtbpHs7pQhIKmqVpxStnY1skuNh4CtbcyOHeX1YBE0hArj2romsFGb6yUmzkq/6M24nkxDqU8GYrKrz+UcA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.11': + resolution: {integrity: sha512-ryHQK2eyDYYMwB5wZL46uoxz2zzDZsFBwfjssgB7pzytAeCCa6glsiJGjhTEddq/4OsIjsLNMAiMlHNYnkEEeg==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.11': + resolution: {integrity: sha512-mYwqheq4BXF83j/w75ewkPJmPZIqqP1nhoghS9D57CLjsh3Nfq0m4ftTotRYtGnZd3eCztgbSPJ9QhfC91gDZQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-musl@4.1.11': + resolution: {integrity: sha512-m/NVRFNGlEHJrNVk3O6I9ggVuNjXHIPoD6bqay/pubtYC9QIdAMpS+cswZQPBLvVvEF6GtSNONbDkZrjWZXYNQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-gnu@4.1.11': + resolution: {integrity: sha512-YW6sblI7xukSD2TdbbaeQVDysIm/UPJtObHJHKxDEcW2exAtY47j52f8jZXkqE1krdnkhCMGqP3dbniu1Te2Fg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-musl@4.1.11': + resolution: {integrity: sha512-e3C/RRhGunWYNC3aSF7exsQkdXzQ/M+aYuZHKnw4U7KQwTJotnWsGOIVih0s2qQzmEzOFIJ3+xt7iq67K/p56Q==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-wasm32-wasi@4.1.11': + resolution: {integrity: sha512-Xo1+/GU0JEN/C/dvcammKHzeM6NqKovG+6921MR6oadee5XPBaKOumrJCXvopJ/Qb5TH7LX/UAywbqrP4lax0g==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.11': + resolution: {integrity: sha512-UgKYx5PwEKrac3GPNPf6HVMNhUIGuUh4wlDFR2jYYdkX6pL/rn73zTq/4pzUm8fOjAn5L8zDeHp9iXmUGOXZ+w==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.1.11': + resolution: {integrity: sha512-YfHoggn1j0LK7wR82TOucWc5LDCguHnoS879idHekmmiR7g9HUtMw9MI0NHatS28u/Xlkfi9w5RJWgz2Dl+5Qg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.1.11': + resolution: {integrity: sha512-Q69XzrtAhuyfHo+5/HMgr1lAiPP/G40OMFAnws7xcFEYqcypZmdW8eGXaOUIeOl1dzPJBPENXgbjsOyhg2nkrg==} + engines: {node: '>= 10'} + + '@tailwindcss/vite@4.1.11': + resolution: {integrity: sha512-RHYhrR3hku0MJFRV+fN2gNbDNEh3dwKvY8XJvTxCSXeMOsCRSr+uKvDWQcbizrHgjML6ZmTE5OwMrl5wKcujCw==} + peerDependencies: + vite: ^5.2.0 || ^6 || ^7 + + '@tanstack/query-core@5.83.1': + resolution: {integrity: sha512-OG69LQgT7jSp+5pPuCfzltq/+7l2xoweggjme9vlbCPa/d7D7zaqv5vN/S82SzSYZ4EDLTxNO1PWrv49RAS64Q==} + + '@tanstack/query-devtools@5.84.0': + resolution: {integrity: sha512-fbF3n+z1rqhvd9EoGp5knHkv3p5B2Zml1yNRjh7sNXklngYI5RVIWUrUjZ1RIcEoscarUb0+bOvIs5x9dwzOXQ==} + + '@tanstack/react-query-devtools@5.84.2': + resolution: {integrity: sha512-ojJ66QoW9noqK35Lsmfqpfucj6wuOxLL2TYwEwpvU+iUQ5R/7TKpapWvpy9kZyNSl0mxv5mpS+ImfR8aL8/x3g==} + peerDependencies: + '@tanstack/react-query': ^5.84.2 + react: ^18 || ^19 + + '@tanstack/react-query@5.84.2': + resolution: {integrity: sha512-cZadySzROlD2+o8zIfbD978p0IphuQzRWiiH3I2ugnTmz4jbjc0+TdibpwqxlzynEen8OulgAg+rzdNF37s7XQ==} + peerDependencies: + react: ^18 || ^19 + + '@types/conventional-commits-parser@5.0.1': + resolution: {integrity: sha512-7uz5EHdzz2TqoMfV7ee61Egf5y6NkcO4FB/1iCCQnbeiI1F3xzv3vK5dBCXUCLQgGYS+mUeigK1iKQzvED+QnQ==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/json5@0.0.29': + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + + '@types/lodash.throttle@4.1.9': + resolution: {integrity: sha512-PCPVfpfueguWZQB7pJQK890F2scYKoDUL3iM522AptHWn7d5NQmeS/LTEHIcLr5PaTzl3dK2Z0xSUHHTHwaL5g==} + + '@types/lodash@4.17.20': + resolution: {integrity: sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA==} + + '@types/node@24.2.1': + resolution: {integrity: sha512-DRh5K+ka5eJic8CjH7td8QpYEV6Zo10gfRkjHCO3weqZHWDtAaSTFtl4+VMqOJ4N5jcuhZ9/l+yy8rVgw7BQeQ==} + + '@types/qs@6.14.0': + resolution: {integrity: sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==} + + '@types/react-dom@19.1.7': + resolution: {integrity: sha512-i5ZzwYpqjmrKenzkoLM2Ibzt6mAsM7pxB6BCIouEVVmgiqaMj1TjaK7hnA36hbW5aZv20kx7Lw6hWzPWg0Rurw==} + peerDependencies: + '@types/react': ^19.0.0 + + '@types/react@19.1.9': + resolution: {integrity: sha512-WmdoynAX8Stew/36uTSVMcLJJ1KRh6L3IZRx1PZ7qJtBqT3dYTgyDTx8H1qoRghErydW7xw9mSJ3wS//tCRpFA==} + + '@types/wordcloud@1.2.2': + resolution: {integrity: sha512-UMKd/doXE3karDUd5l+2LqFKUU4SmuPWOT/VA22OrPOUGMlb8/qQvSf+DBLQf/sd8UphuBGxOK/jB/1BB5oQRw==} + + '@typescript-eslint/eslint-plugin@8.39.0': + resolution: {integrity: sha512-bhEz6OZeUR+O/6yx9Jk6ohX6H9JSFTaiY0v9/PuKT3oGK0rn0jNplLmyFUGV+a9gfYnVNwGDwS/UkLIuXNb2Rw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.39.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/parser@8.39.0': + resolution: {integrity: sha512-g3WpVQHngx0aLXn6kfIYCZxM6rRJlWzEkVpqEFLT3SgEDsp9cpCbxxgwnE504q4H+ruSDh/VGS6nqZIDynP+vg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/project-service@8.39.0': + resolution: {integrity: sha512-CTzJqaSq30V/Z2Og9jogzZt8lJRR5TKlAdXmWgdu4hgcC9Kww5flQ+xFvMxIBWVNdxJO7OifgdOK4PokMIWPew==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/scope-manager@8.39.0': + resolution: {integrity: sha512-8QOzff9UKxOh6npZQ/4FQu4mjdOCGSdO3p44ww0hk8Vu+IGbg0tB/H1LcTARRDzGCC8pDGbh2rissBuuoPgH8A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/tsconfig-utils@8.39.0': + resolution: {integrity: sha512-Fd3/QjmFV2sKmvv3Mrj8r6N8CryYiCS8Wdb/6/rgOXAWGcFuc+VkQuG28uk/4kVNVZBQuuDHEDUpo/pQ32zsIQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/type-utils@8.39.0': + resolution: {integrity: sha512-6B3z0c1DXVT2vYA9+z9axjtc09rqKUPRmijD5m9iv8iQpHBRYRMBcgxSiKTZKm6FwWw1/cI4v6em35OsKCiN5Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/types@8.39.0': + resolution: {integrity: sha512-ArDdaOllnCj3yn/lzKn9s0pBQYmmyme/v1HbGIGB0GB/knFI3fWMHloC+oYTJW46tVbYnGKTMDK4ah1sC2v0Kg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.39.0': + resolution: {integrity: sha512-ndWdiflRMvfIgQRpckQQLiB5qAKQ7w++V4LlCHwp62eym1HLB/kw7D9f2e8ytONls/jt89TEasgvb+VwnRprsw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/utils@8.39.0': + resolution: {integrity: sha512-4GVSvNA0Vx1Ktwvf4sFE+exxJ3QGUorQG1/A5mRfRNZtkBT2xrA/BCO2H0eALx/PnvCS6/vmYwRdDA41EoffkQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/visitor-keys@8.39.0': + resolution: {integrity: sha512-ldgiJ+VAhQCfIjeOgu8Kj5nSxds0ktPOSO9p4+0VDH2R2pLvQraaM5Oen2d7NxzMCm+Sn/vJT+mv2H5u6b/3fA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@vitejs/plugin-react-swc@3.11.0': + resolution: {integrity: sha512-YTJCGFdNMHCMfjODYtxRNVAYmTWQ1Lb8PulP/2/f/oEEtglw8oKxKIZmmRkyXrVrHfsKOaVkAc3NT9/dMutO5w==} + peerDependencies: + vite: ^4 || ^5 || ^6 || ^7 + + JSONStream@1.3.5: + resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} + hasBin: true + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + engines: {node: '>=0.4.0'} + hasBin: true + + add@2.0.6: + resolution: {integrity: sha512-j5QzrmsokwWWp6kUcJQySpbG+xfOBqqKnup3OIk1pz+kB/80SLorZ9V8zHFLO92Lcd+hbvq8bT+zOGoPkmBV0Q==} + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + ajv@8.17.1: + resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + + ansi-escapes@7.0.0: + resolution: {integrity: sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==} + engines: {node: '>=18'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.1.0: + resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} + engines: {node: '>=12'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + aria-query@5.3.2: + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} + + array-buffer-byte-length@1.0.2: + resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} + engines: {node: '>= 0.4'} + + array-ify@1.0.0: + resolution: {integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==} + + array-includes@3.1.9: + resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} + engines: {node: '>= 0.4'} + + array.prototype.findlast@1.2.5: + resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} + engines: {node: '>= 0.4'} + + array.prototype.findlastindex@1.2.6: + resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==} + engines: {node: '>= 0.4'} + + array.prototype.flat@1.3.3: + resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} + engines: {node: '>= 0.4'} + + array.prototype.flatmap@1.3.3: + resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} + engines: {node: '>= 0.4'} + + array.prototype.tosorted@1.1.4: + resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} + engines: {node: '>= 0.4'} + + arraybuffer.prototype.slice@1.0.4: + resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} + engines: {node: '>= 0.4'} + + ast-types-flow@0.0.8: + resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} + + async-function@1.0.0: + resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} + engines: {node: '>= 0.4'} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + autoprefixer@10.4.21: + resolution: {integrity: sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + + available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + + axe-core@4.10.3: + resolution: {integrity: sha512-Xm7bpRXnDSX2YE2YFfBk2FnF0ep6tmG7xPh8iHee8MIcrgq762Nkce856dYtJYLkuIoYZvGfTs/PbZhideTcEg==} + engines: {node: '>=4'} + + axios@1.11.0: + resolution: {integrity: sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==} + + axobject-query@4.1.0: + resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} + engines: {node: '>= 0.4'} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + brace-expansion@1.1.12: + resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} + + brace-expansion@2.0.2: + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browserslist@4.25.2: + resolution: {integrity: sha512-0si2SJK3ooGzIawRu61ZdPCO1IncZwS8IzuX73sPZsXW6EQ/w/DAfPyKI8l1ETTCr2MnvqWitmlCUxgdul45jA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bind@1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + + caniuse-lite@1.0.30001733: + resolution: {integrity: sha512-e4QKw/O2Kavj2VQTKZWrwzkt3IxOmIlU6ajRb6LP64LHpBo1J67k2Hi4Vu/TgJWsNtynurfS0uK3MaUTCPfu5Q==} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + chalk@5.5.0: + resolution: {integrity: sha512-1tm8DTaJhPBG3bIkVeZt1iZM9GfSX2lzOeDVZH9R9ffRHpmHvxZ/QhgQH/aDTkswQVt+YHdXAdS/In/30OjCbg==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + chart.js@4.5.0: + resolution: {integrity: sha512-aYeC/jDgSEx8SHWZvANYMioYMZ2KX02W6f6uVfyteuCGcadDLcYVHdfdygsTQkQ4TKn5lghoojAsPj5pu0SnvQ==} + engines: {pnpm: '>=8'} + + chartjs-plugin-datalabels@2.2.0: + resolution: {integrity: sha512-14ZU30lH7n89oq+A4bWaJPnAG8a7ZTk7dKf48YAzMvJjQtjrgg5Dpk9f+LbjCF6bpx3RAGTeL13IXpKQYyRvlw==} + peerDependencies: + chart.js: '>=3.0.0' + + chownr@3.0.0: + resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} + engines: {node: '>=18'} + + cli-cursor@5.0.0: + resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} + engines: {node: '>=18'} + + cli-truncate@4.0.0: + resolution: {integrity: sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==} + engines: {node: '>=18'} + + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + commander@14.0.0: + resolution: {integrity: sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA==} + engines: {node: '>=20'} + + compare-func@2.0.0: + resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + conventional-changelog-angular@7.0.0: + resolution: {integrity: sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==} + engines: {node: '>=16'} + + conventional-changelog-conventionalcommits@7.0.2: + resolution: {integrity: sha512-NKXYmMR/Hr1DevQegFB4MwfM5Vv0m4UIxKZTTYuD98lpTknaZlSRrDOG4X7wIXpGkfsYxZTghUN+Qq+T0YQI7w==} + engines: {node: '>=16'} + + conventional-commits-parser@5.0.0: + resolution: {integrity: sha512-ZPMl0ZJbw74iS9LuX9YIAiW8pfM5p3yh2o/NbXHbkFuZzY5jvdi5jFycEOkmBW5H5I7nA+D6f3UcsCLP2vvSEA==} + engines: {node: '>=16'} + hasBin: true + + 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'} + + cosmiconfig-typescript-loader@6.1.0: + resolution: {integrity: sha512-tJ1w35ZRUiM5FeTzT7DtYWAFFv37ZLqSRkGi2oeCK1gPhvaWjkAtfXvLmvE1pRfxxp9aQo6ba/Pvg1dKj05D4g==} + engines: {node: '>=v18'} + peerDependencies: + '@types/node': '*' + cosmiconfig: '>=9' + typescript: '>=5' + + cosmiconfig@8.3.6: + resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==} + engines: {node: '>=14'} + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + + cosmiconfig@9.0.0: + resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==} + engines: {node: '>=14'} + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + + damerau-levenshtein@1.0.8: + resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} + + dargs@8.1.0: + resolution: {integrity: sha512-wAV9QHOsNbwnWdNW2FYvE1P56wtgSbM+3SZcdGiWQILwVjACCXDCI3Ai8QlCjMDB8YK5zySiXZYBiwGmNY3lnw==} + engines: {node: '>=12'} + + data-view-buffer@1.0.2: + resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} + engines: {node: '>= 0.4'} + + data-view-byte-length@1.0.2: + resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} + engines: {node: '>= 0.4'} + + data-view-byte-offset@1.0.1: + resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} + engines: {node: '>= 0.4'} + + debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.4.1: + resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + detect-libc@2.0.4: + resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} + engines: {node: '>=8'} + + doctrine@2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} + + dot-case@3.0.4: + resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} + + dot-prop@5.3.0: + resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==} + engines: {node: '>=8'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + electron-to-chromium@1.5.199: + resolution: {integrity: sha512-3gl0S7zQd88kCAZRO/DnxtBKuhMO4h0EaQIN3YgZfV6+pW+5+bf2AdQeHNESCoaQqo/gjGVYEf2YM4O5HJQqpQ==} + + emoji-regex@10.4.0: + resolution: {integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + enhanced-resolve@5.18.3: + resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==} + engines: {node: '>=10.13.0'} + + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + + env-paths@2.2.1: + resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} + engines: {node: '>=6'} + + environment@1.1.0: + resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} + engines: {node: '>=18'} + + error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + + es-abstract@1.24.0: + resolution: {integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==} + engines: {node: '>= 0.4'} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-iterator-helpers@1.2.1: + resolution: {integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + es-shim-unscopables@1.1.0: + resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==} + engines: {node: '>= 0.4'} + + es-to-primitive@1.3.0: + resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} + engines: {node: '>= 0.4'} + + esbuild@0.25.8: + resolution: {integrity: sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q==} + engines: {node: '>=18'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eslint-config-prettier@10.1.8: + resolution: {integrity: sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + + eslint-import-resolver-node@0.3.9: + resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} + + eslint-module-utils@2.12.1: + resolution: {integrity: sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + + eslint-plugin-import-name@1.2.3: + resolution: {integrity: sha512-Fwh+khN9JT78NT75b7AxJGHMYsmpSPJ4Sw3R3GXPWuv8HkYlNLQYIfF11Pv20dcWGrI2Dv4scFn2tlQ4WFQQGA==} + + eslint-plugin-import@2.32.0: + resolution: {integrity: sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + + eslint-plugin-jsx-a11y@6.10.2: + resolution: {integrity: sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==} + engines: {node: '>=4.0'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 + + eslint-plugin-prettier@5.5.4: + resolution: {integrity: sha512-swNtI95SToIz05YINMA6Ox5R057IMAmWZ26GqPxusAp1TZzj+IdY9tXNWWD3vkF/wEqydCONcwjTFpxybBqZsg==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + '@types/eslint': '>=8.0.0' + eslint: '>=8.0.0' + eslint-config-prettier: '>= 7.0.0 <10.0.0 || >=10.1.0' + prettier: '>=3.0.0' + peerDependenciesMeta: + '@types/eslint': + optional: true + eslint-config-prettier: + optional: true + + eslint-plugin-react-hooks@5.2.0: + resolution: {integrity: sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==} + engines: {node: '>=10'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 + + eslint-plugin-react-refresh@0.4.20: + resolution: {integrity: sha512-XpbHQ2q5gUF8BGOX4dHe+71qoirYMhApEPZ7sfhF/dNnOF1UXnCMGZf79SFTBO7Bz5YEIT4TMieSlJBWhP9WBA==} + peerDependencies: + eslint: '>=8.40' + + eslint-plugin-react@7.37.5: + resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==} + engines: {node: '>=4'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 + + eslint-plugin-simple-import-sort@12.1.1: + resolution: {integrity: sha512-6nuzu4xwQtE3332Uz0to+TxDQYRLTKRESSc2hefVT48Zc8JthmN23Gx9lnYhu0FtkRSL1oxny3kJ2aveVhmOVA==} + peerDependencies: + eslint: '>=5.0.0' + + eslint-scope@8.4.0: + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@4.2.1: + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint@9.33.0: + resolution: {integrity: sha512-TS9bTNIryDzStCpJN93aC5VRSW3uTx9sClUn4B87pwiCaJh220otoI0X8mJKr+VcPtniMdN8GKjlwgWGUv5ZKA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + espree@10.4.0: + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + esquery@1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + eventemitter3@5.0.1: + resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-diff@1.3.0: + resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fast-uri@3.0.6: + resolution: {integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==} + + fastq@1.19.1: + resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} + + faye-websocket@0.11.4: + resolution: {integrity: sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==} + engines: {node: '>=0.8.0'} + + fdir@6.4.6: + resolution: {integrity: sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + find-up@7.0.0: + resolution: {integrity: sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==} + engines: {node: '>=18'} + + firebase@12.1.0: + resolution: {integrity: sha512-oZucxvfWKuAW4eHHRqGKzC43fLiPqPwHYBHPRNsnkgonqYaq0VurYgqgBosRlEulW+TWja/5Tpo2FpUU+QrfEQ==} + + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + + flatted@3.3.3: + resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + + follow-redirects@1.15.11: + resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + for-each@0.3.5: + resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} + engines: {node: '>= 0.4'} + + form-data@4.0.4: + resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==} + engines: {node: '>= 6'} + + fraction.js@4.3.7: + resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + function.prototype.name@1.1.8: + resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} + engines: {node: '>= 0.4'} + + functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-east-asian-width@1.3.0: + resolution: {integrity: sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==} + engines: {node: '>=18'} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-symbol-description@1.1.0: + resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} + engines: {node: '>= 0.4'} + + git-raw-commits@4.0.0: + resolution: {integrity: sha512-ICsMM1Wk8xSGMowkOmPrzo2Fgmfo4bMHLNX6ytHjajRJUqvHOw/TFapQ+QG75c3X/tTDDhOSRPGC52dDbNM8FQ==} + engines: {node: '>=16'} + hasBin: true + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + global-directory@4.0.1: + resolution: {integrity: sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==} + engines: {node: '>=18'} + + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + + globals@16.3.0: + resolution: {integrity: sha512-bqWEnJ1Nt3neqx2q5SFfGS8r/ahumIakg3HcwtNlrVlwXIeNumWn/c7Pn/wKzGhf6SaW6H6uWXLqC30STCMchQ==} + engines: {node: '>=18'} + + globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + + has-bigints@1.1.0: + resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} + engines: {node: '>= 0.4'} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-proto@1.2.0: + resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} + engines: {node: '>= 0.4'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + http-parser-js@0.5.10: + resolution: {integrity: sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==} + + husky@9.1.7: + resolution: {integrity: sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==} + engines: {node: '>=18'} + hasBin: true + + idb@7.1.1: + resolution: {integrity: sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + import-meta-resolve@4.1.0: + resolution: {integrity: sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + inherits@2.0.3: + resolution: {integrity: sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==} + + ini@4.1.1: + resolution: {integrity: sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + + internal-slot@1.1.0: + resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} + engines: {node: '>= 0.4'} + + is-array-buffer@3.0.5: + resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} + engines: {node: '>= 0.4'} + + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + is-async-function@2.1.1: + resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} + engines: {node: '>= 0.4'} + + is-bigint@1.1.0: + resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} + engines: {node: '>= 0.4'} + + is-boolean-object@1.2.2: + resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} + engines: {node: '>= 0.4'} + + is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + + is-data-view@1.0.2: + resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} + engines: {node: '>= 0.4'} + + is-date-object@1.1.0: + resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} + engines: {node: '>= 0.4'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-finalizationregistry@1.1.1: + resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} + engines: {node: '>= 0.4'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-fullwidth-code-point@4.0.0: + resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} + engines: {node: '>=12'} + + is-fullwidth-code-point@5.0.0: + resolution: {integrity: sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==} + engines: {node: '>=18'} + + is-generator-function@1.1.0: + resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==} + engines: {node: '>= 0.4'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-map@2.0.3: + resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} + engines: {node: '>= 0.4'} + + is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} + engines: {node: '>= 0.4'} + + is-number-object@1.1.1: + resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} + engines: {node: '>= 0.4'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-obj@2.0.0: + resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} + engines: {node: '>=8'} + + is-regex@1.2.1: + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} + engines: {node: '>= 0.4'} + + is-set@2.0.3: + resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} + engines: {node: '>= 0.4'} + + is-shared-array-buffer@1.0.4: + resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} + engines: {node: '>= 0.4'} + + is-string@1.1.1: + resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} + engines: {node: '>= 0.4'} + + is-symbol@1.1.1: + resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} + engines: {node: '>= 0.4'} + + is-text-path@2.0.0: + resolution: {integrity: sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw==} + engines: {node: '>=8'} + + is-typed-array@1.1.15: + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} + engines: {node: '>= 0.4'} + + is-weakmap@2.0.2: + resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} + engines: {node: '>= 0.4'} + + is-weakref@1.1.1: + resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} + engines: {node: '>= 0.4'} + + is-weakset@2.0.4: + resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} + engines: {node: '>= 0.4'} + + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + iterator.prototype@1.1.5: + resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} + engines: {node: '>= 0.4'} + + jiti@2.5.1: + resolution: {integrity: sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==} + hasBin: true + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + json5@1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + hasBin: true + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + jsonparse@1.3.1: + resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} + engines: {'0': node >= 0.2.0} + + jsx-ast-utils@3.3.5: + resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} + engines: {node: '>=4.0'} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + language-subtag-registry@0.3.23: + resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} + + language-tags@1.0.9: + resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} + engines: {node: '>=0.10'} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + lightningcss-darwin-arm64@1.30.1: + resolution: {integrity: sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.30.1: + resolution: {integrity: sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.30.1: + resolution: {integrity: sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.30.1: + resolution: {integrity: sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.30.1: + resolution: {integrity: sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.30.1: + resolution: {integrity: sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-x64-gnu@1.30.1: + resolution: {integrity: sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.30.1: + resolution: {integrity: sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-win32-arm64-msvc@1.30.1: + resolution: {integrity: sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.30.1: + resolution: {integrity: sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.30.1: + resolution: {integrity: sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==} + engines: {node: '>= 12.0.0'} + + lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} + engines: {node: '>=14'} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + lint-staged@16.1.5: + resolution: {integrity: sha512-uAeQQwByI6dfV7wpt/gVqg+jAPaSp8WwOA8kKC/dv1qw14oGpnpAisY65ibGHUGDUv0rYaZ8CAJZ/1U8hUvC2A==} + engines: {node: '>=20.17'} + hasBin: true + + listr2@9.0.1: + resolution: {integrity: sha512-SL0JY3DaxylDuo/MecFeiC+7pedM0zia33zl0vcjgwcq1q1FWWF1To9EIauPbl8GbMCU0R2e0uJ8bZunhYKD2g==} + engines: {node: '>=20.0.0'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + locate-path@7.2.0: + resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + lodash.camelcase@4.3.0: + resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} + + lodash.isplainobject@4.0.6: + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + + lodash.kebabcase@4.1.1: + resolution: {integrity: sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lodash.mergewith@4.6.2: + resolution: {integrity: sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==} + + lodash.snakecase@4.1.1: + resolution: {integrity: sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==} + + lodash.startcase@4.4.0: + resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} + + lodash.throttle@4.1.1: + resolution: {integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==} + + lodash.uniq@4.5.0: + resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} + + lodash.upperfirst@4.3.1: + resolution: {integrity: sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==} + + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + + log-update@6.1.0: + resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} + engines: {node: '>=18'} + + long@5.3.2: + resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} + + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + + lower-case@2.0.2: + resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + magic-string@0.30.17: + resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + meow@12.1.1: + resolution: {integrity: sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==} + engines: {node: '>=16.10'} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mimic-function@5.0.1: + resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} + engines: {node: '>=18'} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + + minizlib@3.0.2: + resolution: {integrity: sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==} + engines: {node: '>= 18'} + + mkdirp@3.0.1: + resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==} + engines: {node: '>=10'} + hasBin: true + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nano-spawn@1.0.2: + resolution: {integrity: sha512-21t+ozMQDAL/UGgQVBbZ/xXvNO10++ZPuTmKRO8k9V3AClVRht49ahtDjfY8l1q6nSHOrE5ASfthzH3ol6R/hg==} + engines: {node: '>=20.17'} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + no-case@3.0.4: + resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} + + node-releases@2.0.19: + resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} + + normalize-range@0.1.2: + resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} + engines: {node: '>=0.10.0'} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + object.assign@4.1.7: + resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} + engines: {node: '>= 0.4'} + + object.entries@1.1.9: + resolution: {integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==} + engines: {node: '>= 0.4'} + + object.fromentries@2.0.8: + resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} + engines: {node: '>= 0.4'} + + object.groupby@1.0.3: + resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} + engines: {node: '>= 0.4'} + + object.values@1.2.1: + resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} + engines: {node: '>= 0.4'} + + onetime@7.0.0: + resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} + engines: {node: '>=18'} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + own-keys@1.0.1: + resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} + engines: {node: '>= 0.4'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-limit@4.0.0: + resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + p-locate@6.0.0: + resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-exists@5.0.0: + resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + path@0.12.7: + resolution: {integrity: sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + + pidtree@0.6.0: + resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==} + engines: {node: '>=0.10'} + hasBin: true + + possible-typed-array-names@1.1.0: + resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} + engines: {node: '>= 0.4'} + + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prettier-linter-helpers@1.0.0: + resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} + engines: {node: '>=6.0.0'} + + prettier@3.6.2: + resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==} + engines: {node: '>=14'} + hasBin: true + + process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + + prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + + protobufjs@7.5.3: + resolution: {integrity: sha512-sildjKwVqOI2kmFDiXQ6aEB0fjYTafpEvIBs8tOR8qI4spuL9OPROLVu2qZqi/xgCfsHIwVqlaF8JBjWFHnKbw==} + engines: {node: '>=12.0.0'} + + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + react-chartjs-2@5.3.0: + resolution: {integrity: sha512-UfZZFnDsERI3c3CZGxzvNJd02SHjaSJ8kgW1djn65H1KK8rehwTjyrRKOG3VTMG8wtHZ5rgAO5oTHtHi9GCCmw==} + peerDependencies: + chart.js: ^4.1.1 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + react-dom@19.1.1: + resolution: {integrity: sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==} + peerDependencies: + react: ^19.1.1 + + react-hook-form@7.62.0: + resolution: {integrity: sha512-7KWFejc98xqG/F4bAxpL41NB3o1nnvQO1RWZT3TqRZYL8RryQETGfEdVnJN2fy1crCiBLLjkRBVK05j24FxJGA==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^16.8.0 || ^17 || ^18 || ^19 + + react-intersection-observer@9.16.0: + resolution: {integrity: sha512-w9nJSEp+DrW9KmQmeWHQyfaP6b03v+TdXynaoA964Wxt7mdR3An11z4NNCQgL4gKSK7y1ver2Fq+JKH6CWEzUA==} + peerDependencies: + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + react-dom: + optional: true + + react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + + react-router-dom@7.8.0: + resolution: {integrity: sha512-ntInsnDVnVRdtSu6ODmTQ41cbluak/ENeTif7GBce0L6eztFg6/e1hXAysFQI8X25C8ipKmT9cClbJwxx3Kaqw==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: '>=18' + react-dom: '>=18' + + react-router@7.8.0: + resolution: {integrity: sha512-r15M3+LHKgM4SOapNmsH3smAizWds1vJ0Z9C4mWaKnT9/wD7+d/0jYcj6LmOvonkrO4Rgdyp4KQ/29gWN2i1eg==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: '>=18' + react-dom: '>=18' + peerDependenciesMeta: + react-dom: + optional: true + + react-spinners@0.17.0: + resolution: {integrity: sha512-L/8HTylaBmIWwQzIjMq+0vyaRXuoAevzWoD35wKpNTxxtYXWZp+xtgkfD7Y4WItuX0YvdxMPU79+7VhhmbmuTQ==} + peerDependencies: + react: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + react@19.1.1: + resolution: {integrity: sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==} + engines: {node: '>=0.10.0'} + + reflect.getprototypeof@1.0.10: + resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} + engines: {node: '>= 0.4'} + + regexp.prototype.flags@1.5.4: + resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} + engines: {node: '>= 0.4'} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + + resolve@1.22.10: + resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} + engines: {node: '>= 0.4'} + hasBin: true + + resolve@2.0.0-next.5: + resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} + hasBin: true + + restore-cursor@5.1.0: + resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} + engines: {node: '>=18'} + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rfdc@1.4.1: + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + + rollup@4.46.2: + resolution: {integrity: sha512-WMmLFI+Boh6xbop+OAGo9cQ3OgX9MIg7xOQjn+pTCwOkk+FNDAeAemXkJ3HzDJrVXleLOFVa1ipuc1AmEx1Dwg==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + safe-array-concat@1.1.3: + resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} + engines: {node: '>=0.4'} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safe-push-apply@1.0.0: + resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} + engines: {node: '>= 0.4'} + + safe-regex-test@1.1.0: + resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} + engines: {node: '>= 0.4'} + + scheduler@0.26.0: + resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.7.2: + resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} + engines: {node: '>=10'} + hasBin: true + + set-cookie-parser@2.7.1: + resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==} + + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} + + set-proto@1.0.0: + resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} + engines: {node: '>= 0.4'} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + slice-ansi@5.0.0: + resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} + engines: {node: '>=12'} + + slice-ansi@7.1.0: + resolution: {integrity: sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==} + engines: {node: '>=18'} + + snake-case@3.0.4: + resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} + + sonner@2.0.7: + resolution: {integrity: sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==} + peerDependencies: + react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + + stop-iteration-iterator@1.1.0: + resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} + engines: {node: '>= 0.4'} + + string-argv@0.3.2: + resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} + engines: {node: '>=0.6.19'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@7.2.0: + resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} + engines: {node: '>=18'} + + string.prototype.includes@2.0.1: + resolution: {integrity: sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==} + engines: {node: '>= 0.4'} + + string.prototype.matchall@4.0.12: + resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} + engines: {node: '>= 0.4'} + + string.prototype.repeat@1.0.0: + resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} + + string.prototype.trim@1.2.10: + resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} + engines: {node: '>= 0.4'} + + string.prototype.trimend@1.0.9: + resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} + engines: {node: '>= 0.4'} + + string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + svg-parser@2.0.4: + resolution: {integrity: sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==} + + synckit@0.11.11: + resolution: {integrity: sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==} + engines: {node: ^14.18.0 || >=16.0.0} + + tailwindcss@4.1.11: + resolution: {integrity: sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA==} + + tapable@2.2.2: + resolution: {integrity: sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==} + engines: {node: '>=6'} + + tar@7.4.3: + resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==} + engines: {node: '>=18'} + + text-extensions@2.4.0: + resolution: {integrity: sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g==} + engines: {node: '>=8'} + + through@2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + + tinyexec@1.0.1: + resolution: {integrity: sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==} + + tinyglobby@0.2.14: + resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} + engines: {node: '>=12.0.0'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + ts-api-utils@2.1.0: + resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + + tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + typed-array-buffer@1.0.3: + resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} + engines: {node: '>= 0.4'} + + typed-array-byte-length@1.0.3: + resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} + engines: {node: '>= 0.4'} + + typed-array-byte-offset@1.0.4: + resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} + engines: {node: '>= 0.4'} + + typed-array-length@1.0.7: + resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} + engines: {node: '>= 0.4'} + + typescript-eslint@8.39.0: + resolution: {integrity: sha512-lH8FvtdtzcHJCkMOKnN73LIn6SLTpoojgJqDAxPm1jCR14eWSGPX8ul/gggBdPMk/d5+u9V854vTYQ8T5jF/1Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + typescript@5.8.3: + resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} + engines: {node: '>=14.17'} + hasBin: true + + unbox-primitive@1.1.0: + resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} + engines: {node: '>= 0.4'} + + undici-types@7.10.0: + resolution: {integrity: sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==} + + unicorn-magic@0.1.0: + resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==} + engines: {node: '>=18'} + + update-browserslist-db@1.1.3: + resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + util@0.10.4: + resolution: {integrity: sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==} + + vite-plugin-svgr@4.3.0: + resolution: {integrity: sha512-Jy9qLB2/PyWklpYy0xk0UU3TlU0t2UMpJXZvf+hWII1lAmRHrOUKi11Uw8N3rxoNk7atZNYO3pR3vI1f7oi+6w==} + peerDependencies: + vite: '>=2.6.0' + + vite@7.1.1: + resolution: {integrity: sha512-yJ+Mp7OyV+4S+afWo+QyoL9jFWD11QFH0i5i7JypnfTcA1rmgxCbiA8WwAICDEtZ1Z1hzrVhN8R8rGTqkTY8ZQ==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + jiti: '>=1.21.0' + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + web-vitals@4.2.4: + resolution: {integrity: sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==} + + websocket-driver@0.7.4: + resolution: {integrity: sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==} + engines: {node: '>=0.8.0'} + + websocket-extensions@0.1.4: + resolution: {integrity: sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==} + engines: {node: '>=0.8.0'} + + which-boxed-primitive@1.1.1: + resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} + engines: {node: '>= 0.4'} + + which-builtin-type@1.2.1: + resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} + engines: {node: '>= 0.4'} + + which-collection@1.0.2: + resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} + engines: {node: '>= 0.4'} + + which-typed-array@1.1.19: + resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==} + engines: {node: '>= 0.4'} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + wordcloud@1.2.3: + resolution: {integrity: sha512-9by77b7Sd9e1K75kSmVeAD+JnGpiLR1Z4EX1mYQL91jKrU1/4bHw4h4DExQ+dzfT+PvihDcH7OS7V4Y5UkbF2w==} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@9.0.0: + resolution: {integrity: sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==} + engines: {node: '>=18'} + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yallist@5.0.0: + resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} + engines: {node: '>=18'} + + yaml@2.8.1: + resolution: {integrity: sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==} + engines: {node: '>= 14.6'} + hasBin: true + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + yocto-queue@1.2.1: + resolution: {integrity: sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==} + engines: {node: '>=12.20'} + + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + + zustand@5.0.7: + resolution: {integrity: sha512-Ot6uqHDW/O2VdYsKLLU8GQu8sCOM1LcoE8RwvLv9uuRT9s6SOHCKs0ZEOhxg+I1Ld+A1Q5lwx+UlKXXUoCZITg==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=18.0.0' + immer: '>=9.0.6' + react: '>=18.0.0' + use-sync-external-store: '>=1.2.0' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + use-sync-external-store: + optional: true + +snapshots: + + '@ampproject/remapping@2.3.0': + dependencies: + '@jridgewell/gen-mapping': 0.3.12 + '@jridgewell/trace-mapping': 0.3.29 + + '@babel/code-frame@7.27.1': + dependencies: + '@babel/helper-validator-identifier': 7.27.1 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.28.0': {} + + '@babel/core@7.28.0': + dependencies: + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.0 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-module-transforms': 7.27.3(@babel/core@7.28.0) + '@babel/helpers': 7.28.2 + '@babel/parser': 7.28.0 + '@babel/template': 7.27.2 + '@babel/traverse': 7.28.0 + '@babel/types': 7.28.2 + convert-source-map: 2.0.0 + debug: 4.4.1 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.28.0': + dependencies: + '@babel/parser': 7.28.0 + '@babel/types': 7.28.2 + '@jridgewell/gen-mapping': 0.3.12 + '@jridgewell/trace-mapping': 0.3.29 + jsesc: 3.1.0 + + '@babel/helper-compilation-targets@7.27.2': + dependencies: + '@babel/compat-data': 7.28.0 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.25.2 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-globals@7.28.0': {} + + '@babel/helper-module-imports@7.27.1': + dependencies: + '@babel/traverse': 7.28.0 + '@babel/types': 7.28.2 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.27.3(@babel/core@7.28.0)': + dependencies: + '@babel/core': 7.28.0 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + '@babel/traverse': 7.28.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.27.1': {} + + '@babel/helper-validator-option@7.27.1': {} + + '@babel/helpers@7.28.2': + dependencies: + '@babel/template': 7.27.2 + '@babel/types': 7.28.2 + + '@babel/parser@7.28.0': + dependencies: + '@babel/types': 7.28.2 + + '@babel/template@7.27.2': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/parser': 7.28.0 + '@babel/types': 7.28.2 + + '@babel/traverse@7.28.0': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.0 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.28.0 + '@babel/template': 7.27.2 + '@babel/types': 7.28.2 + debug: 4.4.1 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.28.2': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + + '@commitlint/cli@19.8.1(@types/node@24.2.1)(typescript@5.8.3)': + dependencies: + '@commitlint/format': 19.8.1 + '@commitlint/lint': 19.8.1 + '@commitlint/load': 19.8.1(@types/node@24.2.1)(typescript@5.8.3) + '@commitlint/read': 19.8.1 + '@commitlint/types': 19.8.1 + tinyexec: 1.0.1 + yargs: 17.7.2 + transitivePeerDependencies: + - '@types/node' + - typescript + + '@commitlint/config-conventional@19.8.1': + dependencies: + '@commitlint/types': 19.8.1 + conventional-changelog-conventionalcommits: 7.0.2 + + '@commitlint/config-validator@19.8.1': + dependencies: + '@commitlint/types': 19.8.1 + ajv: 8.17.1 + + '@commitlint/ensure@19.8.1': + dependencies: + '@commitlint/types': 19.8.1 + lodash.camelcase: 4.3.0 + lodash.kebabcase: 4.1.1 + lodash.snakecase: 4.1.1 + lodash.startcase: 4.4.0 + lodash.upperfirst: 4.3.1 + + '@commitlint/execute-rule@19.8.1': {} + + '@commitlint/format@19.8.1': + dependencies: + '@commitlint/types': 19.8.1 + chalk: 5.5.0 + + '@commitlint/is-ignored@19.8.1': + dependencies: + '@commitlint/types': 19.8.1 + semver: 7.7.2 + + '@commitlint/lint@19.8.1': + dependencies: + '@commitlint/is-ignored': 19.8.1 + '@commitlint/parse': 19.8.1 + '@commitlint/rules': 19.8.1 + '@commitlint/types': 19.8.1 + + '@commitlint/load@19.8.1(@types/node@24.2.1)(typescript@5.8.3)': + dependencies: + '@commitlint/config-validator': 19.8.1 + '@commitlint/execute-rule': 19.8.1 + '@commitlint/resolve-extends': 19.8.1 + '@commitlint/types': 19.8.1 + chalk: 5.5.0 + cosmiconfig: 9.0.0(typescript@5.8.3) + cosmiconfig-typescript-loader: 6.1.0(@types/node@24.2.1)(cosmiconfig@9.0.0(typescript@5.8.3))(typescript@5.8.3) + lodash.isplainobject: 4.0.6 + lodash.merge: 4.6.2 + lodash.uniq: 4.5.0 + transitivePeerDependencies: + - '@types/node' + - typescript + + '@commitlint/message@19.8.1': {} + + '@commitlint/parse@19.8.1': + dependencies: + '@commitlint/types': 19.8.1 + conventional-changelog-angular: 7.0.0 + conventional-commits-parser: 5.0.0 + + '@commitlint/read@19.8.1': + dependencies: + '@commitlint/top-level': 19.8.1 + '@commitlint/types': 19.8.1 + git-raw-commits: 4.0.0 + minimist: 1.2.8 + tinyexec: 1.0.1 + + '@commitlint/resolve-extends@19.8.1': + dependencies: + '@commitlint/config-validator': 19.8.1 + '@commitlint/types': 19.8.1 + global-directory: 4.0.1 + import-meta-resolve: 4.1.0 + lodash.mergewith: 4.6.2 + resolve-from: 5.0.0 + + '@commitlint/rules@19.8.1': + dependencies: + '@commitlint/ensure': 19.8.1 + '@commitlint/message': 19.8.1 + '@commitlint/to-lines': 19.8.1 + '@commitlint/types': 19.8.1 + + '@commitlint/to-lines@19.8.1': {} + + '@commitlint/top-level@19.8.1': + dependencies: + find-up: 7.0.0 + + '@commitlint/types@19.8.1': + dependencies: + '@types/conventional-commits-parser': 5.0.1 + chalk: 5.5.0 + + '@esbuild/aix-ppc64@0.25.8': + optional: true + + '@esbuild/android-arm64@0.25.8': + optional: true + + '@esbuild/android-arm@0.25.8': + optional: true + + '@esbuild/android-x64@0.25.8': + optional: true + + '@esbuild/darwin-arm64@0.25.8': + optional: true + + '@esbuild/darwin-x64@0.25.8': + optional: true + + '@esbuild/freebsd-arm64@0.25.8': + optional: true + + '@esbuild/freebsd-x64@0.25.8': + optional: true + + '@esbuild/linux-arm64@0.25.8': + optional: true + + '@esbuild/linux-arm@0.25.8': + optional: true + + '@esbuild/linux-ia32@0.25.8': + optional: true + + '@esbuild/linux-loong64@0.25.8': + optional: true + + '@esbuild/linux-mips64el@0.25.8': + optional: true + + '@esbuild/linux-ppc64@0.25.8': + optional: true + + '@esbuild/linux-riscv64@0.25.8': + optional: true + + '@esbuild/linux-s390x@0.25.8': + optional: true + + '@esbuild/linux-x64@0.25.8': + optional: true + + '@esbuild/netbsd-arm64@0.25.8': + optional: true + + '@esbuild/netbsd-x64@0.25.8': + optional: true + + '@esbuild/openbsd-arm64@0.25.8': + optional: true + + '@esbuild/openbsd-x64@0.25.8': + optional: true + + '@esbuild/openharmony-arm64@0.25.8': + optional: true + + '@esbuild/sunos-x64@0.25.8': + optional: true + + '@esbuild/win32-arm64@0.25.8': + optional: true + + '@esbuild/win32-ia32@0.25.8': + optional: true + + '@esbuild/win32-x64@0.25.8': + optional: true + + '@eslint-community/eslint-utils@4.7.0(eslint@9.33.0(jiti@2.5.1))': + dependencies: + eslint: 9.33.0(jiti@2.5.1) + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.1': {} + + '@eslint/config-array@0.21.0': + dependencies: + '@eslint/object-schema': 2.1.6 + debug: 4.4.1 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.3.1': {} + + '@eslint/core@0.15.2': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/eslintrc@3.3.1': + dependencies: + ajv: 6.12.6 + debug: 4.4.1 + espree: 10.4.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.33.0': {} + + '@eslint/object-schema@2.1.6': {} + + '@eslint/plugin-kit@0.3.5': + dependencies: + '@eslint/core': 0.15.2 + levn: 0.4.1 + + '@firebase/ai@2.1.0(@firebase/app-types@0.9.3)(@firebase/app@0.14.1)': + dependencies: + '@firebase/app': 0.14.1 + '@firebase/app-check-interop-types': 0.3.3 + '@firebase/app-types': 0.9.3 + '@firebase/component': 0.7.0 + '@firebase/logger': 0.5.0 + '@firebase/util': 1.13.0 + tslib: 2.8.1 + + '@firebase/analytics-compat@0.2.24(@firebase/app-compat@0.5.1)(@firebase/app@0.14.1)': + dependencies: + '@firebase/analytics': 0.10.18(@firebase/app@0.14.1) + '@firebase/analytics-types': 0.8.3 + '@firebase/app-compat': 0.5.1 + '@firebase/component': 0.7.0 + '@firebase/util': 1.13.0 + tslib: 2.8.1 + transitivePeerDependencies: + - '@firebase/app' + + '@firebase/analytics-types@0.8.3': {} + + '@firebase/analytics@0.10.18(@firebase/app@0.14.1)': + dependencies: + '@firebase/app': 0.14.1 + '@firebase/component': 0.7.0 + '@firebase/installations': 0.6.19(@firebase/app@0.14.1) + '@firebase/logger': 0.5.0 + '@firebase/util': 1.13.0 + tslib: 2.8.1 + + '@firebase/app-check-compat@0.4.0(@firebase/app-compat@0.5.1)(@firebase/app@0.14.1)': + dependencies: + '@firebase/app-check': 0.11.0(@firebase/app@0.14.1) + '@firebase/app-check-types': 0.5.3 + '@firebase/app-compat': 0.5.1 + '@firebase/component': 0.7.0 + '@firebase/logger': 0.5.0 + '@firebase/util': 1.13.0 + tslib: 2.8.1 + transitivePeerDependencies: + - '@firebase/app' + + '@firebase/app-check-interop-types@0.3.3': {} + + '@firebase/app-check-types@0.5.3': {} + + '@firebase/app-check@0.11.0(@firebase/app@0.14.1)': + dependencies: + '@firebase/app': 0.14.1 + '@firebase/component': 0.7.0 + '@firebase/logger': 0.5.0 + '@firebase/util': 1.13.0 + tslib: 2.8.1 + + '@firebase/app-compat@0.5.1': + dependencies: + '@firebase/app': 0.14.1 + '@firebase/component': 0.7.0 + '@firebase/logger': 0.5.0 + '@firebase/util': 1.13.0 + tslib: 2.8.1 + + '@firebase/app-types@0.9.3': {} + + '@firebase/app@0.14.1': + dependencies: + '@firebase/component': 0.7.0 + '@firebase/logger': 0.5.0 + '@firebase/util': 1.13.0 + idb: 7.1.1 + tslib: 2.8.1 + + '@firebase/auth-compat@0.6.0(@firebase/app-compat@0.5.1)(@firebase/app-types@0.9.3)(@firebase/app@0.14.1)': + dependencies: + '@firebase/app-compat': 0.5.1 + '@firebase/auth': 1.11.0(@firebase/app@0.14.1) + '@firebase/auth-types': 0.13.0(@firebase/app-types@0.9.3)(@firebase/util@1.13.0) + '@firebase/component': 0.7.0 + '@firebase/util': 1.13.0 + tslib: 2.8.1 + transitivePeerDependencies: + - '@firebase/app' + - '@firebase/app-types' + - '@react-native-async-storage/async-storage' + + '@firebase/auth-interop-types@0.2.4': {} + + '@firebase/auth-types@0.13.0(@firebase/app-types@0.9.3)(@firebase/util@1.13.0)': + dependencies: + '@firebase/app-types': 0.9.3 + '@firebase/util': 1.13.0 + + '@firebase/auth@1.11.0(@firebase/app@0.14.1)': + dependencies: + '@firebase/app': 0.14.1 + '@firebase/component': 0.7.0 + '@firebase/logger': 0.5.0 + '@firebase/util': 1.13.0 + tslib: 2.8.1 + + '@firebase/component@0.7.0': + dependencies: + '@firebase/util': 1.13.0 + tslib: 2.8.1 + + '@firebase/data-connect@0.3.11(@firebase/app@0.14.1)': + dependencies: + '@firebase/app': 0.14.1 + '@firebase/auth-interop-types': 0.2.4 + '@firebase/component': 0.7.0 + '@firebase/logger': 0.5.0 + '@firebase/util': 1.13.0 + tslib: 2.8.1 + + '@firebase/database-compat@2.1.0': + dependencies: + '@firebase/component': 0.7.0 + '@firebase/database': 1.1.0 + '@firebase/database-types': 1.0.16 + '@firebase/logger': 0.5.0 + '@firebase/util': 1.13.0 + tslib: 2.8.1 + + '@firebase/database-types@1.0.16': + dependencies: + '@firebase/app-types': 0.9.3 + '@firebase/util': 1.13.0 + + '@firebase/database@1.1.0': + dependencies: + '@firebase/app-check-interop-types': 0.3.3 + '@firebase/auth-interop-types': 0.2.4 + '@firebase/component': 0.7.0 + '@firebase/logger': 0.5.0 + '@firebase/util': 1.13.0 + faye-websocket: 0.11.4 + tslib: 2.8.1 + + '@firebase/firestore-compat@0.4.0(@firebase/app-compat@0.5.1)(@firebase/app-types@0.9.3)(@firebase/app@0.14.1)': + dependencies: + '@firebase/app-compat': 0.5.1 + '@firebase/component': 0.7.0 + '@firebase/firestore': 4.9.0(@firebase/app@0.14.1) + '@firebase/firestore-types': 3.0.3(@firebase/app-types@0.9.3)(@firebase/util@1.13.0) + '@firebase/util': 1.13.0 + tslib: 2.8.1 + transitivePeerDependencies: + - '@firebase/app' + - '@firebase/app-types' + + '@firebase/firestore-types@3.0.3(@firebase/app-types@0.9.3)(@firebase/util@1.13.0)': + dependencies: + '@firebase/app-types': 0.9.3 + '@firebase/util': 1.13.0 + + '@firebase/firestore@4.9.0(@firebase/app@0.14.1)': + dependencies: + '@firebase/app': 0.14.1 + '@firebase/component': 0.7.0 + '@firebase/logger': 0.5.0 + '@firebase/util': 1.13.0 + '@firebase/webchannel-wrapper': 1.0.4 + '@grpc/grpc-js': 1.9.15 + '@grpc/proto-loader': 0.7.15 + tslib: 2.8.1 + + '@firebase/functions-compat@0.4.0(@firebase/app-compat@0.5.1)(@firebase/app@0.14.1)': + dependencies: + '@firebase/app-compat': 0.5.1 + '@firebase/component': 0.7.0 + '@firebase/functions': 0.13.0(@firebase/app@0.14.1) + '@firebase/functions-types': 0.6.3 + '@firebase/util': 1.13.0 + tslib: 2.8.1 + transitivePeerDependencies: + - '@firebase/app' + + '@firebase/functions-types@0.6.3': {} + + '@firebase/functions@0.13.0(@firebase/app@0.14.1)': + dependencies: + '@firebase/app': 0.14.1 + '@firebase/app-check-interop-types': 0.3.3 + '@firebase/auth-interop-types': 0.2.4 + '@firebase/component': 0.7.0 + '@firebase/messaging-interop-types': 0.2.3 + '@firebase/util': 1.13.0 + tslib: 2.8.1 + + '@firebase/installations-compat@0.2.19(@firebase/app-compat@0.5.1)(@firebase/app-types@0.9.3)(@firebase/app@0.14.1)': + dependencies: + '@firebase/app-compat': 0.5.1 + '@firebase/component': 0.7.0 + '@firebase/installations': 0.6.19(@firebase/app@0.14.1) + '@firebase/installations-types': 0.5.3(@firebase/app-types@0.9.3) + '@firebase/util': 1.13.0 + tslib: 2.8.1 + transitivePeerDependencies: + - '@firebase/app' + - '@firebase/app-types' + + '@firebase/installations-types@0.5.3(@firebase/app-types@0.9.3)': + dependencies: + '@firebase/app-types': 0.9.3 + + '@firebase/installations@0.6.19(@firebase/app@0.14.1)': + dependencies: + '@firebase/app': 0.14.1 + '@firebase/component': 0.7.0 + '@firebase/util': 1.13.0 + idb: 7.1.1 + tslib: 2.8.1 + + '@firebase/logger@0.5.0': + dependencies: + tslib: 2.8.1 + + '@firebase/messaging-compat@0.2.23(@firebase/app-compat@0.5.1)(@firebase/app@0.14.1)': + dependencies: + '@firebase/app-compat': 0.5.1 + '@firebase/component': 0.7.0 + '@firebase/messaging': 0.12.23(@firebase/app@0.14.1) + '@firebase/util': 1.13.0 + tslib: 2.8.1 + transitivePeerDependencies: + - '@firebase/app' + + '@firebase/messaging-interop-types@0.2.3': {} + + '@firebase/messaging@0.12.23(@firebase/app@0.14.1)': + dependencies: + '@firebase/app': 0.14.1 + '@firebase/component': 0.7.0 + '@firebase/installations': 0.6.19(@firebase/app@0.14.1) + '@firebase/messaging-interop-types': 0.2.3 + '@firebase/util': 1.13.0 + idb: 7.1.1 + tslib: 2.8.1 + + '@firebase/performance-compat@0.2.22(@firebase/app-compat@0.5.1)(@firebase/app@0.14.1)': + dependencies: + '@firebase/app-compat': 0.5.1 + '@firebase/component': 0.7.0 + '@firebase/logger': 0.5.0 + '@firebase/performance': 0.7.9(@firebase/app@0.14.1) + '@firebase/performance-types': 0.2.3 + '@firebase/util': 1.13.0 + tslib: 2.8.1 + transitivePeerDependencies: + - '@firebase/app' + + '@firebase/performance-types@0.2.3': {} + + '@firebase/performance@0.7.9(@firebase/app@0.14.1)': + dependencies: + '@firebase/app': 0.14.1 + '@firebase/component': 0.7.0 + '@firebase/installations': 0.6.19(@firebase/app@0.14.1) + '@firebase/logger': 0.5.0 + '@firebase/util': 1.13.0 + tslib: 2.8.1 + web-vitals: 4.2.4 + + '@firebase/remote-config-compat@0.2.19(@firebase/app-compat@0.5.1)(@firebase/app@0.14.1)': + dependencies: + '@firebase/app-compat': 0.5.1 + '@firebase/component': 0.7.0 + '@firebase/logger': 0.5.0 + '@firebase/remote-config': 0.6.6(@firebase/app@0.14.1) + '@firebase/remote-config-types': 0.4.0 + '@firebase/util': 1.13.0 + tslib: 2.8.1 + transitivePeerDependencies: + - '@firebase/app' + + '@firebase/remote-config-types@0.4.0': {} + + '@firebase/remote-config@0.6.6(@firebase/app@0.14.1)': + dependencies: + '@firebase/app': 0.14.1 + '@firebase/component': 0.7.0 + '@firebase/installations': 0.6.19(@firebase/app@0.14.1) + '@firebase/logger': 0.5.0 + '@firebase/util': 1.13.0 + tslib: 2.8.1 + + '@firebase/storage-compat@0.4.0(@firebase/app-compat@0.5.1)(@firebase/app-types@0.9.3)(@firebase/app@0.14.1)': + dependencies: + '@firebase/app-compat': 0.5.1 + '@firebase/component': 0.7.0 + '@firebase/storage': 0.14.0(@firebase/app@0.14.1) + '@firebase/storage-types': 0.8.3(@firebase/app-types@0.9.3)(@firebase/util@1.13.0) + '@firebase/util': 1.13.0 + tslib: 2.8.1 + transitivePeerDependencies: + - '@firebase/app' + - '@firebase/app-types' + + '@firebase/storage-types@0.8.3(@firebase/app-types@0.9.3)(@firebase/util@1.13.0)': + dependencies: + '@firebase/app-types': 0.9.3 + '@firebase/util': 1.13.0 + + '@firebase/storage@0.14.0(@firebase/app@0.14.1)': + dependencies: + '@firebase/app': 0.14.1 + '@firebase/component': 0.7.0 + '@firebase/util': 1.13.0 + tslib: 2.8.1 + + '@firebase/util@1.13.0': + dependencies: + tslib: 2.8.1 + + '@firebase/webchannel-wrapper@1.0.4': {} + + '@grpc/grpc-js@1.9.15': + dependencies: + '@grpc/proto-loader': 0.7.15 + '@types/node': 24.2.1 + + '@grpc/proto-loader@0.7.15': + dependencies: + lodash.camelcase: 4.3.0 + long: 5.3.2 + protobufjs: 7.5.3 + yargs: 17.7.2 + + '@hookform/resolvers@5.2.1(react-hook-form@7.62.0(react@19.1.1))': + dependencies: + '@standard-schema/utils': 0.3.0 + react-hook-form: 7.62.0(react@19.1.1) + + '@humanfs/core@0.19.1': {} + + '@humanfs/node@0.16.6': + dependencies: + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.3.1 + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.3.1': {} + + '@humanwhocodes/retry@0.4.3': {} + + '@isaacs/fs-minipass@4.0.1': + dependencies: + minipass: 7.1.2 + + '@jridgewell/gen-mapping@0.3.12': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.4 + '@jridgewell/trace-mapping': 0.3.29 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.4': {} + + '@jridgewell/trace-mapping@0.3.29': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.4 + + '@kurkle/color@0.3.4': {} + + '@lukemorales/query-key-factory@1.3.4(@tanstack/query-core@5.83.1)(@tanstack/react-query@5.84.2(react@19.1.1))': + dependencies: + '@tanstack/query-core': 5.83.1 + '@tanstack/react-query': 5.84.2(react@19.1.1) + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.19.1 + + '@pkgr/core@0.2.9': {} + + '@protobufjs/aspromise@1.1.2': {} + + '@protobufjs/base64@1.1.2': {} + + '@protobufjs/codegen@2.0.4': {} + + '@protobufjs/eventemitter@1.1.0': {} + + '@protobufjs/fetch@1.1.0': + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/inquire': 1.1.0 + + '@protobufjs/float@1.0.2': {} + + '@protobufjs/inquire@1.1.0': {} + + '@protobufjs/path@1.1.2': {} + + '@protobufjs/pool@1.1.0': {} + + '@protobufjs/utf8@1.1.0': {} + + '@rolldown/pluginutils@1.0.0-beta.27': {} + + '@rollup/pluginutils@5.2.0(rollup@4.46.2)': + dependencies: + '@types/estree': 1.0.8 + estree-walker: 2.0.2 + picomatch: 4.0.3 + optionalDependencies: + rollup: 4.46.2 + + '@rollup/rollup-android-arm-eabi@4.46.2': + optional: true + + '@rollup/rollup-android-arm64@4.46.2': + optional: true + + '@rollup/rollup-darwin-arm64@4.46.2': + optional: true + + '@rollup/rollup-darwin-x64@4.46.2': + optional: true + + '@rollup/rollup-freebsd-arm64@4.46.2': + optional: true + + '@rollup/rollup-freebsd-x64@4.46.2': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.46.2': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.46.2': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.46.2': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.46.2': + optional: true + + '@rollup/rollup-linux-loongarch64-gnu@4.46.2': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.46.2': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.46.2': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.46.2': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.46.2': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.46.2': + optional: true + + '@rollup/rollup-linux-x64-musl@4.46.2': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.46.2': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.46.2': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.46.2': + optional: true + + '@rtsao/scc@1.1.0': {} + + '@standard-schema/utils@0.3.0': {} + + '@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.28.0)': + dependencies: + '@babel/core': 7.28.0 + + '@svgr/babel-plugin-remove-jsx-attribute@8.0.0(@babel/core@7.28.0)': + dependencies: + '@babel/core': 7.28.0 + + '@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0(@babel/core@7.28.0)': + dependencies: + '@babel/core': 7.28.0 + + '@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0(@babel/core@7.28.0)': + dependencies: + '@babel/core': 7.28.0 + + '@svgr/babel-plugin-svg-dynamic-title@8.0.0(@babel/core@7.28.0)': + dependencies: + '@babel/core': 7.28.0 + + '@svgr/babel-plugin-svg-em-dimensions@8.0.0(@babel/core@7.28.0)': + dependencies: + '@babel/core': 7.28.0 + + '@svgr/babel-plugin-transform-react-native-svg@8.1.0(@babel/core@7.28.0)': + dependencies: + '@babel/core': 7.28.0 + + '@svgr/babel-plugin-transform-svg-component@8.0.0(@babel/core@7.28.0)': + dependencies: + '@babel/core': 7.28.0 + + '@svgr/babel-preset@8.1.0(@babel/core@7.28.0)': + dependencies: + '@babel/core': 7.28.0 + '@svgr/babel-plugin-add-jsx-attribute': 8.0.0(@babel/core@7.28.0) + '@svgr/babel-plugin-remove-jsx-attribute': 8.0.0(@babel/core@7.28.0) + '@svgr/babel-plugin-remove-jsx-empty-expression': 8.0.0(@babel/core@7.28.0) + '@svgr/babel-plugin-replace-jsx-attribute-value': 8.0.0(@babel/core@7.28.0) + '@svgr/babel-plugin-svg-dynamic-title': 8.0.0(@babel/core@7.28.0) + '@svgr/babel-plugin-svg-em-dimensions': 8.0.0(@babel/core@7.28.0) + '@svgr/babel-plugin-transform-react-native-svg': 8.1.0(@babel/core@7.28.0) + '@svgr/babel-plugin-transform-svg-component': 8.0.0(@babel/core@7.28.0) + + '@svgr/core@8.1.0(typescript@5.8.3)': + dependencies: + '@babel/core': 7.28.0 + '@svgr/babel-preset': 8.1.0(@babel/core@7.28.0) + camelcase: 6.3.0 + cosmiconfig: 8.3.6(typescript@5.8.3) + snake-case: 3.0.4 + transitivePeerDependencies: + - supports-color + - typescript + + '@svgr/hast-util-to-babel-ast@8.0.0': + dependencies: + '@babel/types': 7.28.2 + entities: 4.5.0 + + '@svgr/plugin-jsx@8.1.0(@svgr/core@8.1.0(typescript@5.8.3))': + dependencies: + '@babel/core': 7.28.0 + '@svgr/babel-preset': 8.1.0(@babel/core@7.28.0) + '@svgr/core': 8.1.0(typescript@5.8.3) + '@svgr/hast-util-to-babel-ast': 8.0.0 + svg-parser: 2.0.4 + transitivePeerDependencies: + - supports-color + + '@swc/core-darwin-arm64@1.13.3': + optional: true + + '@swc/core-darwin-x64@1.13.3': + optional: true + + '@swc/core-linux-arm-gnueabihf@1.13.3': + optional: true + + '@swc/core-linux-arm64-gnu@1.13.3': + optional: true + + '@swc/core-linux-arm64-musl@1.13.3': + optional: true + + '@swc/core-linux-x64-gnu@1.13.3': + optional: true + + '@swc/core-linux-x64-musl@1.13.3': + optional: true + + '@swc/core-win32-arm64-msvc@1.13.3': + optional: true + + '@swc/core-win32-ia32-msvc@1.13.3': + optional: true + + '@swc/core-win32-x64-msvc@1.13.3': + optional: true + + '@swc/core@1.13.3': + dependencies: + '@swc/counter': 0.1.3 + '@swc/types': 0.1.24 + optionalDependencies: + '@swc/core-darwin-arm64': 1.13.3 + '@swc/core-darwin-x64': 1.13.3 + '@swc/core-linux-arm-gnueabihf': 1.13.3 + '@swc/core-linux-arm64-gnu': 1.13.3 + '@swc/core-linux-arm64-musl': 1.13.3 + '@swc/core-linux-x64-gnu': 1.13.3 + '@swc/core-linux-x64-musl': 1.13.3 + '@swc/core-win32-arm64-msvc': 1.13.3 + '@swc/core-win32-ia32-msvc': 1.13.3 + '@swc/core-win32-x64-msvc': 1.13.3 + + '@swc/counter@0.1.3': {} + + '@swc/types@0.1.24': + dependencies: + '@swc/counter': 0.1.3 + + '@tailwindcss/node@4.1.11': + dependencies: + '@ampproject/remapping': 2.3.0 + enhanced-resolve: 5.18.3 + jiti: 2.5.1 + lightningcss: 1.30.1 + magic-string: 0.30.17 + source-map-js: 1.2.1 + tailwindcss: 4.1.11 + + '@tailwindcss/oxide-android-arm64@4.1.11': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.1.11': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.1.11': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.1.11': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.11': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.11': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.1.11': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.1.11': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.1.11': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.1.11': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.11': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.1.11': + optional: true + + '@tailwindcss/oxide@4.1.11': + dependencies: + detect-libc: 2.0.4 + tar: 7.4.3 + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.1.11 + '@tailwindcss/oxide-darwin-arm64': 4.1.11 + '@tailwindcss/oxide-darwin-x64': 4.1.11 + '@tailwindcss/oxide-freebsd-x64': 4.1.11 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.11 + '@tailwindcss/oxide-linux-arm64-gnu': 4.1.11 + '@tailwindcss/oxide-linux-arm64-musl': 4.1.11 + '@tailwindcss/oxide-linux-x64-gnu': 4.1.11 + '@tailwindcss/oxide-linux-x64-musl': 4.1.11 + '@tailwindcss/oxide-wasm32-wasi': 4.1.11 + '@tailwindcss/oxide-win32-arm64-msvc': 4.1.11 + '@tailwindcss/oxide-win32-x64-msvc': 4.1.11 + + '@tailwindcss/vite@4.1.11(vite@7.1.1(@types/node@24.2.1)(jiti@2.5.1)(lightningcss@1.30.1)(yaml@2.8.1))': + dependencies: + '@tailwindcss/node': 4.1.11 + '@tailwindcss/oxide': 4.1.11 + tailwindcss: 4.1.11 + vite: 7.1.1(@types/node@24.2.1)(jiti@2.5.1)(lightningcss@1.30.1)(yaml@2.8.1) + + '@tanstack/query-core@5.83.1': {} + + '@tanstack/query-devtools@5.84.0': {} + + '@tanstack/react-query-devtools@5.84.2(@tanstack/react-query@5.84.2(react@19.1.1))(react@19.1.1)': + dependencies: + '@tanstack/query-devtools': 5.84.0 + '@tanstack/react-query': 5.84.2(react@19.1.1) + react: 19.1.1 + + '@tanstack/react-query@5.84.2(react@19.1.1)': + dependencies: + '@tanstack/query-core': 5.83.1 + react: 19.1.1 + + '@types/conventional-commits-parser@5.0.1': + dependencies: + '@types/node': 24.2.1 + + '@types/estree@1.0.8': {} + + '@types/json-schema@7.0.15': {} + + '@types/json5@0.0.29': {} + + '@types/lodash.throttle@4.1.9': + dependencies: + '@types/lodash': 4.17.20 + + '@types/lodash@4.17.20': {} + + '@types/node@24.2.1': + dependencies: + undici-types: 7.10.0 + + '@types/qs@6.14.0': {} + + '@types/react-dom@19.1.7(@types/react@19.1.9)': + dependencies: + '@types/react': 19.1.9 + + '@types/react@19.1.9': + dependencies: + csstype: 3.1.3 + + '@types/wordcloud@1.2.2': {} + + '@typescript-eslint/eslint-plugin@8.39.0(@typescript-eslint/parser@8.39.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3)': + dependencies: + '@eslint-community/regexpp': 4.12.1 + '@typescript-eslint/parser': 8.39.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3) + '@typescript-eslint/scope-manager': 8.39.0 + '@typescript-eslint/type-utils': 8.39.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3) + '@typescript-eslint/utils': 8.39.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3) + '@typescript-eslint/visitor-keys': 8.39.0 + eslint: 9.33.0(jiti@2.5.1) + graphemer: 1.4.0 + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.1.0(typescript@5.8.3) + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.39.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.39.0 + '@typescript-eslint/types': 8.39.0 + '@typescript-eslint/typescript-estree': 8.39.0(typescript@5.8.3) + '@typescript-eslint/visitor-keys': 8.39.0 + debug: 4.4.1 + eslint: 9.33.0(jiti@2.5.1) + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.39.0(typescript@5.8.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.39.0(typescript@5.8.3) + '@typescript-eslint/types': 8.39.0 + debug: 4.4.1 + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.39.0': + dependencies: + '@typescript-eslint/types': 8.39.0 + '@typescript-eslint/visitor-keys': 8.39.0 + + '@typescript-eslint/tsconfig-utils@8.39.0(typescript@5.8.3)': + dependencies: + typescript: 5.8.3 + + '@typescript-eslint/type-utils@8.39.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3)': + dependencies: + '@typescript-eslint/types': 8.39.0 + '@typescript-eslint/typescript-estree': 8.39.0(typescript@5.8.3) + '@typescript-eslint/utils': 8.39.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3) + debug: 4.4.1 + eslint: 9.33.0(jiti@2.5.1) + ts-api-utils: 2.1.0(typescript@5.8.3) + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@8.39.0': {} + + '@typescript-eslint/typescript-estree@8.39.0(typescript@5.8.3)': + dependencies: + '@typescript-eslint/project-service': 8.39.0(typescript@5.8.3) + '@typescript-eslint/tsconfig-utils': 8.39.0(typescript@5.8.3) + '@typescript-eslint/types': 8.39.0 + '@typescript-eslint/visitor-keys': 8.39.0 + debug: 4.4.1 + fast-glob: 3.3.3 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.7.2 + ts-api-utils: 2.1.0(typescript@5.8.3) + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.39.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3)': + dependencies: + '@eslint-community/eslint-utils': 4.7.0(eslint@9.33.0(jiti@2.5.1)) + '@typescript-eslint/scope-manager': 8.39.0 + '@typescript-eslint/types': 8.39.0 + '@typescript-eslint/typescript-estree': 8.39.0(typescript@5.8.3) + eslint: 9.33.0(jiti@2.5.1) + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.39.0': + dependencies: + '@typescript-eslint/types': 8.39.0 + eslint-visitor-keys: 4.2.1 + + '@vitejs/plugin-react-swc@3.11.0(vite@7.1.1(@types/node@24.2.1)(jiti@2.5.1)(lightningcss@1.30.1)(yaml@2.8.1))': + dependencies: + '@rolldown/pluginutils': 1.0.0-beta.27 + '@swc/core': 1.13.3 + vite: 7.1.1(@types/node@24.2.1)(jiti@2.5.1)(lightningcss@1.30.1)(yaml@2.8.1) + transitivePeerDependencies: + - '@swc/helpers' + + JSONStream@1.3.5: + dependencies: + jsonparse: 1.3.1 + through: 2.3.8 + + acorn-jsx@5.3.2(acorn@8.15.0): + dependencies: + acorn: 8.15.0 + + acorn@8.15.0: {} + + add@2.0.6: {} + + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ajv@8.17.1: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.0.6 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + ansi-escapes@7.0.0: + dependencies: + environment: 1.1.0 + + ansi-regex@5.0.1: {} + + ansi-regex@6.1.0: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@6.2.1: {} + + argparse@2.0.1: {} + + aria-query@5.3.2: {} + + array-buffer-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + is-array-buffer: 3.0.5 + + array-ify@1.0.0: {} + + array-includes@3.1.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + is-string: 1.1.1 + math-intrinsics: 1.1.0 + + array.prototype.findlast@1.2.5: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-shim-unscopables: 1.1.0 + + array.prototype.findlastindex@1.2.6: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-shim-unscopables: 1.1.0 + + array.prototype.flat@1.3.3: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-shim-unscopables: 1.1.0 + + array.prototype.flatmap@1.3.3: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-shim-unscopables: 1.1.0 + + array.prototype.tosorted@1.1.4: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-shim-unscopables: 1.1.0 + + arraybuffer.prototype.slice@1.0.4: + dependencies: + array-buffer-byte-length: 1.0.2 + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + is-array-buffer: 3.0.5 + + ast-types-flow@0.0.8: {} + + async-function@1.0.0: {} + + asynckit@0.4.0: {} + + autoprefixer@10.4.21(postcss@8.5.6): + dependencies: + browserslist: 4.25.2 + caniuse-lite: 1.0.30001733 + fraction.js: 4.3.7 + normalize-range: 0.1.2 + picocolors: 1.1.1 + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.1.0 + + axe-core@4.10.3: {} + + axios@1.11.0: + dependencies: + follow-redirects: 1.15.11 + form-data: 4.0.4 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + + axobject-query@4.1.0: {} + + balanced-match@1.0.2: {} + + brace-expansion@1.1.12: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.2: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browserslist@4.25.2: + dependencies: + caniuse-lite: 1.0.30001733 + electron-to-chromium: 1.5.199 + node-releases: 2.0.19 + update-browserslist-db: 1.1.3(browserslist@4.25.2) + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bind@1.0.8: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + get-intrinsic: 1.3.0 + set-function-length: 1.2.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + callsites@3.1.0: {} + + camelcase@6.3.0: {} + + caniuse-lite@1.0.30001733: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + chalk@5.5.0: {} + + chart.js@4.5.0: + dependencies: + '@kurkle/color': 0.3.4 + + chartjs-plugin-datalabels@2.2.0(chart.js@4.5.0): + dependencies: + chart.js: 4.5.0 + + chownr@3.0.0: {} + + cli-cursor@5.0.0: + dependencies: + restore-cursor: 5.1.0 + + cli-truncate@4.0.0: + dependencies: + slice-ansi: 5.0.0 + string-width: 7.2.0 + + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + clsx@2.1.1: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + colorette@2.0.20: {} + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + commander@14.0.0: {} + + compare-func@2.0.0: + dependencies: + array-ify: 1.0.0 + dot-prop: 5.3.0 + + concat-map@0.0.1: {} + + conventional-changelog-angular@7.0.0: + dependencies: + compare-func: 2.0.0 + + conventional-changelog-conventionalcommits@7.0.2: + dependencies: + compare-func: 2.0.0 + + conventional-commits-parser@5.0.0: + dependencies: + JSONStream: 1.3.5 + is-text-path: 2.0.0 + meow: 12.1.1 + split2: 4.2.0 + + convert-source-map@2.0.0: {} + + cookie@1.0.2: {} + + cosmiconfig-typescript-loader@6.1.0(@types/node@24.2.1)(cosmiconfig@9.0.0(typescript@5.8.3))(typescript@5.8.3): + dependencies: + '@types/node': 24.2.1 + cosmiconfig: 9.0.0(typescript@5.8.3) + jiti: 2.5.1 + typescript: 5.8.3 + + cosmiconfig@8.3.6(typescript@5.8.3): + dependencies: + import-fresh: 3.3.1 + js-yaml: 4.1.0 + parse-json: 5.2.0 + path-type: 4.0.0 + optionalDependencies: + typescript: 5.8.3 + + cosmiconfig@9.0.0(typescript@5.8.3): + dependencies: + env-paths: 2.2.1 + import-fresh: 3.3.1 + js-yaml: 4.1.0 + parse-json: 5.2.0 + optionalDependencies: + typescript: 5.8.3 + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + csstype@3.1.3: {} + + damerau-levenshtein@1.0.8: {} + + dargs@8.1.0: {} + + data-view-buffer@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-offset@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + debug@3.2.7: + dependencies: + ms: 2.1.3 + + debug@4.4.1: + dependencies: + ms: 2.1.3 + + deep-is@0.1.4: {} + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + + define-properties@1.2.1: + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + + delayed-stream@1.0.0: {} + + detect-libc@2.0.4: {} + + doctrine@2.1.0: + dependencies: + esutils: 2.0.3 + + dot-case@3.0.4: + dependencies: + no-case: 3.0.4 + tslib: 2.8.1 + + dot-prop@5.3.0: + dependencies: + is-obj: 2.0.0 + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + electron-to-chromium@1.5.199: {} + + emoji-regex@10.4.0: {} + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + + enhanced-resolve@5.18.3: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.2.2 + + entities@4.5.0: {} + + env-paths@2.2.1: {} + + environment@1.1.0: {} + + error-ex@1.3.2: + dependencies: + is-arrayish: 0.2.1 + + es-abstract@1.24.0: + dependencies: + array-buffer-byte-length: 1.0.2 + arraybuffer.prototype.slice: 1.0.4 + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + data-view-buffer: 1.0.2 + data-view-byte-length: 1.0.2 + data-view-byte-offset: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-set-tostringtag: 2.1.0 + es-to-primitive: 1.3.0 + function.prototype.name: 1.1.8 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + get-symbol-description: 1.1.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + internal-slot: 1.1.0 + is-array-buffer: 3.0.5 + is-callable: 1.2.7 + is-data-view: 1.0.2 + is-negative-zero: 2.0.3 + is-regex: 1.2.1 + is-set: 2.0.3 + is-shared-array-buffer: 1.0.4 + is-string: 1.1.1 + is-typed-array: 1.1.15 + is-weakref: 1.1.1 + math-intrinsics: 1.1.0 + object-inspect: 1.13.4 + object-keys: 1.1.1 + object.assign: 4.1.7 + own-keys: 1.0.1 + regexp.prototype.flags: 1.5.4 + safe-array-concat: 1.1.3 + safe-push-apply: 1.0.0 + safe-regex-test: 1.1.0 + set-proto: 1.0.0 + stop-iteration-iterator: 1.1.0 + string.prototype.trim: 1.2.10 + string.prototype.trimend: 1.0.9 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.3 + typed-array-byte-length: 1.0.3 + typed-array-byte-offset: 1.0.4 + typed-array-length: 1.0.7 + unbox-primitive: 1.1.0 + which-typed-array: 1.1.19 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-iterator-helpers@1.2.1: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-set-tostringtag: 2.1.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + iterator.prototype: 1.1.5 + safe-array-concat: 1.1.3 + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + es-shim-unscopables@1.1.0: + dependencies: + hasown: 2.0.2 + + es-to-primitive@1.3.0: + dependencies: + is-callable: 1.2.7 + is-date-object: 1.1.0 + is-symbol: 1.1.1 + + esbuild@0.25.8: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.8 + '@esbuild/android-arm': 0.25.8 + '@esbuild/android-arm64': 0.25.8 + '@esbuild/android-x64': 0.25.8 + '@esbuild/darwin-arm64': 0.25.8 + '@esbuild/darwin-x64': 0.25.8 + '@esbuild/freebsd-arm64': 0.25.8 + '@esbuild/freebsd-x64': 0.25.8 + '@esbuild/linux-arm': 0.25.8 + '@esbuild/linux-arm64': 0.25.8 + '@esbuild/linux-ia32': 0.25.8 + '@esbuild/linux-loong64': 0.25.8 + '@esbuild/linux-mips64el': 0.25.8 + '@esbuild/linux-ppc64': 0.25.8 + '@esbuild/linux-riscv64': 0.25.8 + '@esbuild/linux-s390x': 0.25.8 + '@esbuild/linux-x64': 0.25.8 + '@esbuild/netbsd-arm64': 0.25.8 + '@esbuild/netbsd-x64': 0.25.8 + '@esbuild/openbsd-arm64': 0.25.8 + '@esbuild/openbsd-x64': 0.25.8 + '@esbuild/openharmony-arm64': 0.25.8 + '@esbuild/sunos-x64': 0.25.8 + '@esbuild/win32-arm64': 0.25.8 + '@esbuild/win32-ia32': 0.25.8 + '@esbuild/win32-x64': 0.25.8 + + escalade@3.2.0: {} + + escape-string-regexp@4.0.0: {} + + eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.5.1)): + dependencies: + eslint: 9.33.0(jiti@2.5.1) + + eslint-import-resolver-node@0.3.9: + dependencies: + debug: 3.2.7 + is-core-module: 2.16.1 + resolve: 1.22.10 + transitivePeerDependencies: + - supports-color + + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.39.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint@9.33.0(jiti@2.5.1)): + dependencies: + debug: 3.2.7 + optionalDependencies: + '@typescript-eslint/parser': 8.39.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3) + eslint: 9.33.0(jiti@2.5.1) + eslint-import-resolver-node: 0.3.9 + transitivePeerDependencies: + - supports-color + + eslint-plugin-import-name@1.2.3: {} + + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.39.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint@9.33.0(jiti@2.5.1)): + dependencies: + '@rtsao/scc': 1.1.0 + array-includes: 3.1.9 + array.prototype.findlastindex: 1.2.6 + array.prototype.flat: 1.3.3 + array.prototype.flatmap: 1.3.3 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 9.33.0(jiti@2.5.1) + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.39.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint@9.33.0(jiti@2.5.1)) + hasown: 2.0.2 + is-core-module: 2.16.1 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.1 + semver: 6.3.1 + string.prototype.trimend: 1.0.9 + tsconfig-paths: 3.15.0 + optionalDependencies: + '@typescript-eslint/parser': 8.39.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3) + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + + eslint-plugin-jsx-a11y@6.10.2(eslint@9.33.0(jiti@2.5.1)): + dependencies: + aria-query: 5.3.2 + array-includes: 3.1.9 + array.prototype.flatmap: 1.3.3 + ast-types-flow: 0.0.8 + axe-core: 4.10.3 + axobject-query: 4.1.0 + damerau-levenshtein: 1.0.8 + emoji-regex: 9.2.2 + eslint: 9.33.0(jiti@2.5.1) + hasown: 2.0.2 + jsx-ast-utils: 3.3.5 + language-tags: 1.0.9 + minimatch: 3.1.2 + object.fromentries: 2.0.8 + safe-regex-test: 1.1.0 + string.prototype.includes: 2.0.1 + + eslint-plugin-prettier@5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.5.1)))(eslint@9.33.0(jiti@2.5.1))(prettier@3.6.2): + dependencies: + eslint: 9.33.0(jiti@2.5.1) + prettier: 3.6.2 + prettier-linter-helpers: 1.0.0 + synckit: 0.11.11 + optionalDependencies: + eslint-config-prettier: 10.1.8(eslint@9.33.0(jiti@2.5.1)) + + eslint-plugin-react-hooks@5.2.0(eslint@9.33.0(jiti@2.5.1)): + dependencies: + eslint: 9.33.0(jiti@2.5.1) + + eslint-plugin-react-refresh@0.4.20(eslint@9.33.0(jiti@2.5.1)): + dependencies: + eslint: 9.33.0(jiti@2.5.1) + + eslint-plugin-react@7.37.5(eslint@9.33.0(jiti@2.5.1)): + dependencies: + array-includes: 3.1.9 + array.prototype.findlast: 1.2.5 + array.prototype.flatmap: 1.3.3 + array.prototype.tosorted: 1.1.4 + doctrine: 2.1.0 + es-iterator-helpers: 1.2.1 + eslint: 9.33.0(jiti@2.5.1) + estraverse: 5.3.0 + hasown: 2.0.2 + jsx-ast-utils: 3.3.5 + minimatch: 3.1.2 + object.entries: 1.1.9 + object.fromentries: 2.0.8 + object.values: 1.2.1 + prop-types: 15.8.1 + resolve: 2.0.0-next.5 + semver: 6.3.1 + string.prototype.matchall: 4.0.12 + string.prototype.repeat: 1.0.0 + + eslint-plugin-simple-import-sort@12.1.1(eslint@9.33.0(jiti@2.5.1)): + dependencies: + eslint: 9.33.0(jiti@2.5.1) + + eslint-scope@8.4.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.1: {} + + eslint@9.33.0(jiti@2.5.1): + dependencies: + '@eslint-community/eslint-utils': 4.7.0(eslint@9.33.0(jiti@2.5.1)) + '@eslint-community/regexpp': 4.12.1 + '@eslint/config-array': 0.21.0 + '@eslint/config-helpers': 0.3.1 + '@eslint/core': 0.15.2 + '@eslint/eslintrc': 3.3.1 + '@eslint/js': 9.33.0 + '@eslint/plugin-kit': 0.3.5 + '@humanfs/node': 0.16.6 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.8 + '@types/json-schema': 7.0.15 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.1 + escape-string-regexp: 4.0.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.6.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + optionalDependencies: + jiti: 2.5.1 + transitivePeerDependencies: + - supports-color + + espree@10.4.0: + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + eslint-visitor-keys: 4.2.1 + + esquery@1.6.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + estree-walker@2.0.2: {} + + esutils@2.0.3: {} + + eventemitter3@5.0.1: {} + + fast-deep-equal@3.1.3: {} + + fast-diff@1.3.0: {} + + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fast-uri@3.0.6: {} + + fastq@1.19.1: + dependencies: + reusify: 1.1.0 + + faye-websocket@0.11.4: + dependencies: + websocket-driver: 0.7.4 + + fdir@6.4.6(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + find-up@7.0.0: + dependencies: + locate-path: 7.2.0 + path-exists: 5.0.0 + unicorn-magic: 0.1.0 + + firebase@12.1.0: + dependencies: + '@firebase/ai': 2.1.0(@firebase/app-types@0.9.3)(@firebase/app@0.14.1) + '@firebase/analytics': 0.10.18(@firebase/app@0.14.1) + '@firebase/analytics-compat': 0.2.24(@firebase/app-compat@0.5.1)(@firebase/app@0.14.1) + '@firebase/app': 0.14.1 + '@firebase/app-check': 0.11.0(@firebase/app@0.14.1) + '@firebase/app-check-compat': 0.4.0(@firebase/app-compat@0.5.1)(@firebase/app@0.14.1) + '@firebase/app-compat': 0.5.1 + '@firebase/app-types': 0.9.3 + '@firebase/auth': 1.11.0(@firebase/app@0.14.1) + '@firebase/auth-compat': 0.6.0(@firebase/app-compat@0.5.1)(@firebase/app-types@0.9.3)(@firebase/app@0.14.1) + '@firebase/data-connect': 0.3.11(@firebase/app@0.14.1) + '@firebase/database': 1.1.0 + '@firebase/database-compat': 2.1.0 + '@firebase/firestore': 4.9.0(@firebase/app@0.14.1) + '@firebase/firestore-compat': 0.4.0(@firebase/app-compat@0.5.1)(@firebase/app-types@0.9.3)(@firebase/app@0.14.1) + '@firebase/functions': 0.13.0(@firebase/app@0.14.1) + '@firebase/functions-compat': 0.4.0(@firebase/app-compat@0.5.1)(@firebase/app@0.14.1) + '@firebase/installations': 0.6.19(@firebase/app@0.14.1) + '@firebase/installations-compat': 0.2.19(@firebase/app-compat@0.5.1)(@firebase/app-types@0.9.3)(@firebase/app@0.14.1) + '@firebase/messaging': 0.12.23(@firebase/app@0.14.1) + '@firebase/messaging-compat': 0.2.23(@firebase/app-compat@0.5.1)(@firebase/app@0.14.1) + '@firebase/performance': 0.7.9(@firebase/app@0.14.1) + '@firebase/performance-compat': 0.2.22(@firebase/app-compat@0.5.1)(@firebase/app@0.14.1) + '@firebase/remote-config': 0.6.6(@firebase/app@0.14.1) + '@firebase/remote-config-compat': 0.2.19(@firebase/app-compat@0.5.1)(@firebase/app@0.14.1) + '@firebase/storage': 0.14.0(@firebase/app@0.14.1) + '@firebase/storage-compat': 0.4.0(@firebase/app-compat@0.5.1)(@firebase/app-types@0.9.3)(@firebase/app@0.14.1) + '@firebase/util': 1.13.0 + transitivePeerDependencies: + - '@react-native-async-storage/async-storage' + + flat-cache@4.0.1: + dependencies: + flatted: 3.3.3 + keyv: 4.5.4 + + flatted@3.3.3: {} + + follow-redirects@1.15.11: {} + + for-each@0.3.5: + dependencies: + is-callable: 1.2.7 + + form-data@4.0.4: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.2 + mime-types: 2.1.35 + + fraction.js@4.3.7: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + function.prototype.name@1.1.8: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + functions-have-names: 1.2.3 + hasown: 2.0.2 + is-callable: 1.2.7 + + functions-have-names@1.2.3: {} + + gensync@1.0.0-beta.2: {} + + get-caller-file@2.0.5: {} + + get-east-asian-width@1.3.0: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + get-symbol-description@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + + git-raw-commits@4.0.0: + dependencies: + dargs: 8.1.0 + meow: 12.1.1 + split2: 4.2.0 + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + global-directory@4.0.1: + dependencies: + ini: 4.1.1 + + globals@14.0.0: {} + + globals@16.3.0: {} + + globalthis@1.0.4: + dependencies: + define-properties: 1.2.1 + gopd: 1.2.0 + + gopd@1.2.0: {} + + graceful-fs@4.2.11: {} + + graphemer@1.4.0: {} + + has-bigints@1.1.0: {} + + has-flag@4.0.0: {} + + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.1 + + has-proto@1.2.0: + dependencies: + dunder-proto: 1.0.1 + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + http-parser-js@0.5.10: {} + + husky@9.1.7: {} + + idb@7.1.1: {} + + ignore@5.3.2: {} + + ignore@7.0.5: {} + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + import-meta-resolve@4.1.0: {} + + imurmurhash@0.1.4: {} + + inherits@2.0.3: {} + + ini@4.1.1: {} + + internal-slot@1.1.0: + dependencies: + es-errors: 1.3.0 + hasown: 2.0.2 + side-channel: 1.1.0 + + is-array-buffer@3.0.5: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + is-arrayish@0.2.1: {} + + is-async-function@2.1.1: + dependencies: + async-function: 1.0.0 + call-bound: 1.0.4 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-bigint@1.1.0: + dependencies: + has-bigints: 1.1.0 + + is-boolean-object@1.2.2: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-callable@1.2.7: {} + + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + + is-data-view@1.0.2: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + is-typed-array: 1.1.15 + + is-date-object@1.1.0: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-extglob@2.1.1: {} + + is-finalizationregistry@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-fullwidth-code-point@3.0.0: {} + + is-fullwidth-code-point@4.0.0: {} + + is-fullwidth-code-point@5.0.0: + dependencies: + get-east-asian-width: 1.3.0 + + is-generator-function@1.1.0: + dependencies: + call-bound: 1.0.4 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-map@2.0.3: {} + + is-negative-zero@2.0.3: {} + + is-number-object@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-number@7.0.0: {} + + is-obj@2.0.0: {} + + is-regex@1.2.1: + dependencies: + call-bound: 1.0.4 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + is-set@2.0.3: {} + + is-shared-array-buffer@1.0.4: + dependencies: + call-bound: 1.0.4 + + is-string@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-symbol@1.1.1: + dependencies: + call-bound: 1.0.4 + has-symbols: 1.1.0 + safe-regex-test: 1.1.0 + + is-text-path@2.0.0: + dependencies: + text-extensions: 2.4.0 + + is-typed-array@1.1.15: + dependencies: + which-typed-array: 1.1.19 + + is-weakmap@2.0.2: {} + + is-weakref@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-weakset@2.0.4: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + isarray@2.0.5: {} + + isexe@2.0.0: {} + + iterator.prototype@1.1.5: + dependencies: + define-data-property: 1.1.4 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + has-symbols: 1.1.0 + set-function-name: 2.0.2 + + jiti@2.5.1: {} + + js-tokens@4.0.0: {} + + js-yaml@4.1.0: + dependencies: + argparse: 2.0.1 + + jsesc@3.1.0: {} + + json-buffer@3.0.1: {} + + json-parse-even-better-errors@2.3.1: {} + + json-schema-traverse@0.4.1: {} + + json-schema-traverse@1.0.0: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json5@1.0.2: + dependencies: + minimist: 1.2.8 + + json5@2.2.3: {} + + jsonparse@1.3.1: {} + + jsx-ast-utils@3.3.5: + dependencies: + array-includes: 3.1.9 + array.prototype.flat: 1.3.3 + object.assign: 4.1.7 + object.values: 1.2.1 + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + language-subtag-registry@0.3.23: {} + + language-tags@1.0.9: + dependencies: + language-subtag-registry: 0.3.23 + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + lightningcss-darwin-arm64@1.30.1: + optional: true + + lightningcss-darwin-x64@1.30.1: + optional: true + + lightningcss-freebsd-x64@1.30.1: + optional: true + + lightningcss-linux-arm-gnueabihf@1.30.1: + optional: true + + lightningcss-linux-arm64-gnu@1.30.1: + optional: true + + lightningcss-linux-arm64-musl@1.30.1: + optional: true + + lightningcss-linux-x64-gnu@1.30.1: + optional: true + + lightningcss-linux-x64-musl@1.30.1: + optional: true + + lightningcss-win32-arm64-msvc@1.30.1: + optional: true + + lightningcss-win32-x64-msvc@1.30.1: + optional: true + + lightningcss@1.30.1: + dependencies: + detect-libc: 2.0.4 + optionalDependencies: + lightningcss-darwin-arm64: 1.30.1 + lightningcss-darwin-x64: 1.30.1 + lightningcss-freebsd-x64: 1.30.1 + lightningcss-linux-arm-gnueabihf: 1.30.1 + lightningcss-linux-arm64-gnu: 1.30.1 + lightningcss-linux-arm64-musl: 1.30.1 + lightningcss-linux-x64-gnu: 1.30.1 + lightningcss-linux-x64-musl: 1.30.1 + lightningcss-win32-arm64-msvc: 1.30.1 + lightningcss-win32-x64-msvc: 1.30.1 + + lilconfig@3.1.3: {} + + lines-and-columns@1.2.4: {} + + lint-staged@16.1.5: + dependencies: + chalk: 5.5.0 + commander: 14.0.0 + debug: 4.4.1 + lilconfig: 3.1.3 + listr2: 9.0.1 + micromatch: 4.0.8 + nano-spawn: 1.0.2 + pidtree: 0.6.0 + string-argv: 0.3.2 + yaml: 2.8.1 + transitivePeerDependencies: + - supports-color + + listr2@9.0.1: + dependencies: + cli-truncate: 4.0.0 + colorette: 2.0.20 + eventemitter3: 5.0.1 + log-update: 6.1.0 + rfdc: 1.4.1 + wrap-ansi: 9.0.0 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + locate-path@7.2.0: + dependencies: + p-locate: 6.0.0 + + lodash.camelcase@4.3.0: {} + + lodash.isplainobject@4.0.6: {} + + lodash.kebabcase@4.1.1: {} + + lodash.merge@4.6.2: {} + + lodash.mergewith@4.6.2: {} + + lodash.snakecase@4.1.1: {} + + lodash.startcase@4.4.0: {} + + lodash.throttle@4.1.1: {} + + lodash.uniq@4.5.0: {} + + lodash.upperfirst@4.3.1: {} + + lodash@4.17.21: {} + + log-update@6.1.0: + dependencies: + ansi-escapes: 7.0.0 + cli-cursor: 5.0.0 + slice-ansi: 7.1.0 + strip-ansi: 7.1.0 + wrap-ansi: 9.0.0 + + long@5.3.2: {} + + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + + lower-case@2.0.2: + dependencies: + tslib: 2.8.1 + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + magic-string@0.30.17: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.4 + + math-intrinsics@1.1.0: {} + + meow@12.1.1: {} + + merge2@1.4.1: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mimic-function@5.0.1: {} + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.12 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.2 + + minimist@1.2.8: {} + + minipass@7.1.2: {} + + minizlib@3.0.2: + dependencies: + minipass: 7.1.2 + + mkdirp@3.0.1: {} + + ms@2.1.3: {} + + nano-spawn@1.0.2: {} + + nanoid@3.3.11: {} + + natural-compare@1.4.0: {} + + no-case@3.0.4: + dependencies: + lower-case: 2.0.2 + tslib: 2.8.1 + + node-releases@2.0.19: {} + + normalize-range@0.1.2: {} + + object-assign@4.1.1: {} + + object-inspect@1.13.4: {} + + object-keys@1.1.1: {} + + object.assign@4.1.7: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + has-symbols: 1.1.0 + object-keys: 1.1.1 + + object.entries@1.1.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + object.fromentries@2.0.8: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-object-atoms: 1.1.1 + + object.groupby@1.0.3: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + + object.values@1.2.1: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + onetime@7.0.0: + dependencies: + mimic-function: 5.0.1 + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + own-keys@1.0.1: + dependencies: + get-intrinsic: 1.3.0 + object-keys: 1.1.1 + safe-push-apply: 1.0.0 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-limit@4.0.0: + dependencies: + yocto-queue: 1.2.1 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + p-locate@6.0.0: + dependencies: + p-limit: 4.0.0 + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.27.1 + error-ex: 1.3.2 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + + path-exists@4.0.0: {} + + path-exists@5.0.0: {} + + path-key@3.1.1: {} + + path-parse@1.0.7: {} + + path-type@4.0.0: {} + + path@0.12.7: + dependencies: + process: 0.11.10 + util: 0.10.4 + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + picomatch@4.0.3: {} + + pidtree@0.6.0: {} + + possible-typed-array-names@1.1.0: {} + + postcss-value-parser@4.2.0: {} + + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prelude-ls@1.2.1: {} + + prettier-linter-helpers@1.0.0: + dependencies: + fast-diff: 1.3.0 + + prettier@3.6.2: {} + + process@0.11.10: {} + + prop-types@15.8.1: + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 + + protobufjs@7.5.3: + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/base64': 1.1.2 + '@protobufjs/codegen': 2.0.4 + '@protobufjs/eventemitter': 1.1.0 + '@protobufjs/fetch': 1.1.0 + '@protobufjs/float': 1.0.2 + '@protobufjs/inquire': 1.1.0 + '@protobufjs/path': 1.1.2 + '@protobufjs/pool': 1.1.0 + '@protobufjs/utf8': 1.1.0 + '@types/node': 24.2.1 + long: 5.3.2 + + proxy-from-env@1.1.0: {} + + punycode@2.3.1: {} + + queue-microtask@1.2.3: {} + + react-chartjs-2@5.3.0(chart.js@4.5.0)(react@19.1.1): + dependencies: + chart.js: 4.5.0 + react: 19.1.1 + + react-dom@19.1.1(react@19.1.1): + dependencies: + react: 19.1.1 + scheduler: 0.26.0 + + react-hook-form@7.62.0(react@19.1.1): + dependencies: + react: 19.1.1 + + react-intersection-observer@9.16.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1): + dependencies: + react: 19.1.1 + optionalDependencies: + react-dom: 19.1.1(react@19.1.1) + + react-is@16.13.1: {} + + react-router-dom@7.8.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1): + dependencies: + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + react-router: 7.8.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + + react-router@7.8.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1): + dependencies: + cookie: 1.0.2 + react: 19.1.1 + set-cookie-parser: 2.7.1 + optionalDependencies: + react-dom: 19.1.1(react@19.1.1) + + react-spinners@0.17.0(react-dom@19.1.1(react@19.1.1))(react@19.1.1): + dependencies: + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + + react@19.1.1: {} + + reflect.getprototypeof@1.0.10: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + which-builtin-type: 1.2.1 + + regexp.prototype.flags@1.5.4: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-errors: 1.3.0 + get-proto: 1.0.1 + gopd: 1.2.0 + set-function-name: 2.0.2 + + require-directory@2.1.1: {} + + require-from-string@2.0.2: {} + + resolve-from@4.0.0: {} + + resolve-from@5.0.0: {} + + resolve@1.22.10: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + resolve@2.0.0-next.5: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + restore-cursor@5.1.0: + dependencies: + onetime: 7.0.0 + signal-exit: 4.1.0 + + reusify@1.1.0: {} + + rfdc@1.4.1: {} + + rollup@4.46.2: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.46.2 + '@rollup/rollup-android-arm64': 4.46.2 + '@rollup/rollup-darwin-arm64': 4.46.2 + '@rollup/rollup-darwin-x64': 4.46.2 + '@rollup/rollup-freebsd-arm64': 4.46.2 + '@rollup/rollup-freebsd-x64': 4.46.2 + '@rollup/rollup-linux-arm-gnueabihf': 4.46.2 + '@rollup/rollup-linux-arm-musleabihf': 4.46.2 + '@rollup/rollup-linux-arm64-gnu': 4.46.2 + '@rollup/rollup-linux-arm64-musl': 4.46.2 + '@rollup/rollup-linux-loongarch64-gnu': 4.46.2 + '@rollup/rollup-linux-ppc64-gnu': 4.46.2 + '@rollup/rollup-linux-riscv64-gnu': 4.46.2 + '@rollup/rollup-linux-riscv64-musl': 4.46.2 + '@rollup/rollup-linux-s390x-gnu': 4.46.2 + '@rollup/rollup-linux-x64-gnu': 4.46.2 + '@rollup/rollup-linux-x64-musl': 4.46.2 + '@rollup/rollup-win32-arm64-msvc': 4.46.2 + '@rollup/rollup-win32-ia32-msvc': 4.46.2 + '@rollup/rollup-win32-x64-msvc': 4.46.2 + fsevents: 2.3.3 + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + safe-array-concat@1.1.3: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + has-symbols: 1.1.0 + isarray: 2.0.5 + + safe-buffer@5.2.1: {} + + safe-push-apply@1.0.0: + dependencies: + es-errors: 1.3.0 + isarray: 2.0.5 + + safe-regex-test@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-regex: 1.2.1 + + scheduler@0.26.0: {} + + semver@6.3.1: {} + + semver@7.7.2: {} + + set-cookie-parser@2.7.1: {} + + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + + set-function-name@2.0.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + + set-proto@1.0.0: + dependencies: + dunder-proto: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + side-channel-list@1.0.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + signal-exit@4.1.0: {} + + slice-ansi@5.0.0: + dependencies: + ansi-styles: 6.2.1 + is-fullwidth-code-point: 4.0.0 + + slice-ansi@7.1.0: + dependencies: + ansi-styles: 6.2.1 + is-fullwidth-code-point: 5.0.0 + + snake-case@3.0.4: + dependencies: + dot-case: 3.0.4 + tslib: 2.8.1 + + sonner@2.0.7(react-dom@19.1.1(react@19.1.1))(react@19.1.1): + dependencies: + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + + source-map-js@1.2.1: {} + + split2@4.2.0: {} + + stop-iteration-iterator@1.1.0: + dependencies: + es-errors: 1.3.0 + internal-slot: 1.1.0 + + string-argv@0.3.2: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@7.2.0: + dependencies: + emoji-regex: 10.4.0 + get-east-asian-width: 1.3.0 + strip-ansi: 7.1.0 + + string.prototype.includes@2.0.1: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + + string.prototype.matchall@4.0.12: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + regexp.prototype.flags: 1.5.4 + set-function-name: 2.0.2 + side-channel: 1.1.0 + + string.prototype.repeat@1.0.0: + dependencies: + define-properties: 1.2.1 + es-abstract: 1.24.0 + + string.prototype.trim@1.2.10: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-data-property: 1.1.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-object-atoms: 1.1.1 + has-property-descriptors: 1.0.2 + + string.prototype.trimend@1.0.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + string.prototype.trimstart@1.0.8: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.1.0: + dependencies: + ansi-regex: 6.1.0 + + strip-bom@3.0.0: {} + + strip-json-comments@3.1.1: {} + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + svg-parser@2.0.4: {} + + synckit@0.11.11: + dependencies: + '@pkgr/core': 0.2.9 + + tailwindcss@4.1.11: {} + + tapable@2.2.2: {} + + tar@7.4.3: + dependencies: + '@isaacs/fs-minipass': 4.0.1 + chownr: 3.0.0 + minipass: 7.1.2 + minizlib: 3.0.2 + mkdirp: 3.0.1 + yallist: 5.0.0 + + text-extensions@2.4.0: {} + + through@2.3.8: {} + + tinyexec@1.0.1: {} + + tinyglobby@0.2.14: + dependencies: + fdir: 6.4.6(picomatch@4.0.3) + picomatch: 4.0.3 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + ts-api-utils@2.1.0(typescript@5.8.3): + dependencies: + typescript: 5.8.3 + + tsconfig-paths@3.15.0: + dependencies: + '@types/json5': 0.0.29 + json5: 1.0.2 + minimist: 1.2.8 + strip-bom: 3.0.0 + + tslib@2.8.1: {} + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + typed-array-buffer@1.0.3: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-typed-array: 1.1.15 + + typed-array-byte-length@1.0.3: + dependencies: + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + + typed-array-byte-offset@1.0.4: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + reflect.getprototypeof: 1.0.10 + + typed-array-length@1.0.7: + dependencies: + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + is-typed-array: 1.1.15 + possible-typed-array-names: 1.1.0 + reflect.getprototypeof: 1.0.10 + + typescript-eslint@8.39.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.39.0(@typescript-eslint/parser@8.39.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3))(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3) + '@typescript-eslint/parser': 8.39.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3) + '@typescript-eslint/typescript-estree': 8.39.0(typescript@5.8.3) + '@typescript-eslint/utils': 8.39.0(eslint@9.33.0(jiti@2.5.1))(typescript@5.8.3) + eslint: 9.33.0(jiti@2.5.1) + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + typescript@5.8.3: {} + + unbox-primitive@1.1.0: + dependencies: + call-bound: 1.0.4 + has-bigints: 1.1.0 + has-symbols: 1.1.0 + which-boxed-primitive: 1.1.1 + + undici-types@7.10.0: {} + + unicorn-magic@0.1.0: {} + + update-browserslist-db@1.1.3(browserslist@4.25.2): + dependencies: + browserslist: 4.25.2 + escalade: 3.2.0 + picocolors: 1.1.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + util@0.10.4: + dependencies: + inherits: 2.0.3 + + vite-plugin-svgr@4.3.0(rollup@4.46.2)(typescript@5.8.3)(vite@7.1.1(@types/node@24.2.1)(jiti@2.5.1)(lightningcss@1.30.1)(yaml@2.8.1)): + dependencies: + '@rollup/pluginutils': 5.2.0(rollup@4.46.2) + '@svgr/core': 8.1.0(typescript@5.8.3) + '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.8.3)) + vite: 7.1.1(@types/node@24.2.1)(jiti@2.5.1)(lightningcss@1.30.1)(yaml@2.8.1) + transitivePeerDependencies: + - rollup + - supports-color + - typescript + + vite@7.1.1(@types/node@24.2.1)(jiti@2.5.1)(lightningcss@1.30.1)(yaml@2.8.1): + dependencies: + esbuild: 0.25.8 + fdir: 6.4.6(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.46.2 + tinyglobby: 0.2.14 + optionalDependencies: + '@types/node': 24.2.1 + fsevents: 2.3.3 + jiti: 2.5.1 + lightningcss: 1.30.1 + yaml: 2.8.1 + + web-vitals@4.2.4: {} + + websocket-driver@0.7.4: + dependencies: + http-parser-js: 0.5.10 + safe-buffer: 5.2.1 + websocket-extensions: 0.1.4 + + websocket-extensions@0.1.4: {} + + which-boxed-primitive@1.1.1: + dependencies: + is-bigint: 1.1.0 + is-boolean-object: 1.2.2 + is-number-object: 1.1.1 + is-string: 1.1.1 + is-symbol: 1.1.1 + + which-builtin-type@1.2.1: + dependencies: + call-bound: 1.0.4 + function.prototype.name: 1.1.8 + has-tostringtag: 1.0.2 + is-async-function: 2.1.1 + is-date-object: 1.1.0 + is-finalizationregistry: 1.1.1 + is-generator-function: 1.1.0 + is-regex: 1.2.1 + is-weakref: 1.1.1 + isarray: 2.0.5 + which-boxed-primitive: 1.1.1 + which-collection: 1.0.2 + which-typed-array: 1.1.19 + + which-collection@1.0.2: + dependencies: + is-map: 2.0.3 + is-set: 2.0.3 + is-weakmap: 2.0.2 + is-weakset: 2.0.4 + + which-typed-array@1.1.19: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + for-each: 0.3.5 + get-proto: 1.0.1 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + word-wrap@1.2.5: {} + + wordcloud@1.2.3: {} + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@9.0.0: + dependencies: + ansi-styles: 6.2.1 + string-width: 7.2.0 + strip-ansi: 7.1.0 + + y18n@5.0.8: {} + + yallist@3.1.1: {} + + yallist@5.0.0: {} + + yaml@2.8.1: {} + + yargs-parser@21.1.1: {} + + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + + yocto-queue@0.1.0: {} + + yocto-queue@1.2.1: {} + + zod@3.25.76: {} + + zustand@5.0.7(@types/react@19.1.9)(react@19.1.1): + optionalDependencies: + '@types/react': 19.1.9 + react: 19.1.1 diff --git a/src/api/course/course.ts b/src/api/course/course.ts index 356a808..457a65c 100644 --- a/src/api/course/course.ts +++ b/src/api/course/course.ts @@ -1,3 +1,5 @@ +import qs from 'qs'; + import type { TDeleteBookmarkRequest, TDeleteBookmarkResponse, @@ -9,6 +11,8 @@ import type { TPostBookmarkResponse, TPostDateCourseRequest, TPostDateCourseResponse, + TPostMakeBookmarkRequest, + TPostMakeBookmarkResponse, TSearchRegionResponse, TSearchRegionValues, } from '@/types/dateCourse/dateCourse'; @@ -28,17 +32,21 @@ export const postDateCourse = async ({ budget, datePlaces, mealPlan, + dateDurationTime, transportation, userPreferredKeywords, startTime, + excludedCourseSignatures, }: TPostDateCourseRequest): Promise => { const { data } = await axiosInstance.post('/api/v1/date-courses/', { budget, datePlaces, + dateDurationTime, mealPlan, transportation, userPreferredKeywords, startTime, + excludedCourseSignatures, }); return data; }; @@ -47,7 +55,10 @@ export const postBookmark = async ({ dateCourseId }: TPostBookmarkRequest): Prom const { data } = await axiosInstance.post(`/api/v1/date-courses/${dateCourseId}/bookmarks`); return data; }; - +export const postMakeBookmark = async ({ datePlaceIds, name }: TPostMakeBookmarkRequest): Promise => { + const { data } = await axiosInstance.post(`/api/v1/date-courses/bookmarks`, { datePlaceIds, name }); + return data; +}; export const deleteBookmark = async ({ dateCourseId }: TDeleteBookmarkRequest): Promise => { const { data } = await axiosInstance.delete(`/api/v1/date-courses/${dateCourseId}/bookmarks`); return data; @@ -62,7 +73,7 @@ export const getDateCourse = async ({ page, size, }: TGetDateCourseRequest): Promise => { - const { data } = await axiosInstance.get('/api/v1/date-courses/search', { + const { data } = await axiosInstance.get('/api/v1/date-courses', { params: { page, size, @@ -72,6 +83,7 @@ export const getDateCourse = async ({ transportation, userPreferredKeywords, }, + paramsSerializer: (params) => qs.stringify(params, { arrayFormat: 'repeat' }), }); return data; }; diff --git a/src/components/common/navigator.tsx b/src/components/common/navigator.tsx index 9654b2f..2d0d3f3 100644 --- a/src/components/common/navigator.tsx +++ b/src/components/common/navigator.tsx @@ -11,19 +11,20 @@ export default function Navigator({ current, end, onClick }: TNavigatorProps) { const groupSize = 5; // 한 번에 보여줄 페이지 수 const groupStart = Math.floor((current - 1) / groupSize) * groupSize + 1; const groupEnd = Math.min(groupStart + groupSize - 1, end); + const total = Math.max(1, end); - const pages = []; - for (let i = groupStart; i <= groupEnd; i++) { - pages.push(i); + const isFirstGroup = groupStart <= 1; + const isLastGroup = total === 1 ? true : groupEnd >= total; + const pages = Array.from({ length: groupEnd - groupStart + 1 }, (_, i) => groupStart + i); + if (pages.length === 0) { + pages.push(1); } - return (
- {groupStart > 1 && ( - - )} + + {pages.map((page) => ( - )} + +
); } diff --git a/src/components/dateCourse/dateCourse.tsx b/src/components/dateCourse/dateCourse.tsx index b548719..b6efc08 100644 --- a/src/components/dateCourse/dateCourse.tsx +++ b/src/components/dateCourse/dateCourse.tsx @@ -1,6 +1,8 @@ import { useEffect, useRef, useState } from 'react'; -import type { TDateCourse } from '@/types/dateCourse/dateCourse'; +import type { TDateCourse, TDateCourseSearchCondInfo } from '@/types/dateCourse/dateCourse'; + +import useBookmark from '@/hooks/course/useBookmark'; import Info from './info'; import Timeline from './timeline'; @@ -12,20 +14,47 @@ import KeyboardArrowDown from '@/assets/icons/keyboard_arrow_down_False.svg?reac type TDateCourseProps = TDateCourse & { defaultOpen?: boolean; + isBookmarked: boolean; + signature: string; + make?: boolean; + dateCourseSearchCondInfo: TDateCourseSearchCondInfo; }; -function DateCourse({ defaultOpen = false, name, datePlaces }: TDateCourseProps) { +function DateCourse({ defaultOpen = false, name, make, dateCourseId, isBookmarked, datePlaces, dateCourseSearchCondInfo }: TDateCourseProps) { const [open, setOpen] = useState(defaultOpen || false); const [openEdit, setOpenEdit] = useState(false); const [openModal, setOpenModal] = useState(false); - const [isBookmarked, setIsBookmarked] = useState(false); + const [bookmarked, setBookmarked] = useState(isBookmarked); + const [dateCourseID, setDateCourseID] = useState(dateCourseId); const moreRef = useRef(null); + const { usePostBookmark, usePostMakeBookmark } = useBookmark(); + const { mutate: postBookmark } = usePostBookmark; + const { mutate: postMakeBookmark } = usePostMakeBookmark; + const ids = (datePlaces ?? []).map((p) => p.datePlaceId); const clickBookmark = () => { - if (isBookmarked) { + if (bookmarked) { setOpenModal(true); + } else if (make === true) { + postMakeBookmark( + { + datePlaceIds: ids, + name: name, + }, + { + onSuccess: (response) => { + setDateCourseID(response.result.dateCourseId); + setBookmarked(true); + }, + onError: () => { + console.error('북마크 도중 에러가 발생하였습니다.'); + }, + }, + ); } else { - setIsBookmarked(!isBookmarked); + postBookmark({ + dateCourseId: dateCourseID!, + }); } }; @@ -56,7 +85,7 @@ function DateCourse({ defaultOpen = false, name, datePlaces }: TDateCourseProps)
- {isBookmarked ? ( + {bookmarked ? ( ) : ( @@ -74,9 +103,9 @@ function DateCourse({ defaultOpen = false, name, datePlaces }: TDateCourseProps) @@ -87,24 +116,11 @@ function DateCourse({ defaultOpen = false, name, datePlaces }: TDateCourseProps)
@@ -112,11 +128,12 @@ function DateCourse({ defaultOpen = false, name, datePlaces }: TDateCourseProps) )} {openModal && ( { setOpenModal(false); }} changeState={(state: boolean) => { - setIsBookmarked(state); + setBookmarked(state); }} isOpen={openModal} /> diff --git a/src/components/dateCourse/dateCourseSearchFilterOption.tsx b/src/components/dateCourse/dateCourseSearchFilterOption.tsx index ef429c2..8aadc4d 100644 --- a/src/components/dateCourse/dateCourseSearchFilterOption.tsx +++ b/src/components/dateCourse/dateCourseSearchFilterOption.tsx @@ -88,7 +88,17 @@ export default function DateCourseSearchFilterOption({
{type === 'choice' && items?.map(({ label, value: apiValue }, idx) => { - return onChange(apiValue!)} />; + return ( + { + onChange(apiValue!); + console.log('click'); + }} + /> + ); })} {type === 'choices' && @@ -188,7 +198,7 @@ export default function DateCourseSearchFilterOption({ onChange={(e) => { const val = e.target.value; setTime(val); - if (date) onChange(`${date}T${val}:00`); + if (date) onChange(`${date}T${val}:00.000Z`); }} className="absolute top-0 left-0 w-full h-full opacity-0" /> diff --git a/src/components/dateCourse/dateKeyword.tsx b/src/components/dateCourse/dateKeyword.tsx index 44fa25a..961556c 100644 --- a/src/components/dateCourse/dateKeyword.tsx +++ b/src/components/dateCourse/dateKeyword.tsx @@ -17,12 +17,12 @@ export default function DateKeyword({ category, tags, setState, state }: TDat {tags.map((tag) => { return ( { - toggleItem(tag.code); + toggleItem(tag.label); }} /> ); diff --git a/src/components/dateCourse/infoElement.tsx b/src/components/dateCourse/infoElement.tsx index 43dcc4f..793056f 100644 --- a/src/components/dateCourse/infoElement.tsx +++ b/src/components/dateCourse/infoElement.tsx @@ -5,7 +5,7 @@ import KeywordButton from './keywordButton'; type TInfoElement = { children: ReactElement; title: string; - tags: string[] | string; + tags: string[] | string | undefined; }; export default function InfoElement({ children, title, tags }: TInfoElement) { return ( diff --git a/src/components/dateCourse/timeline.tsx b/src/components/dateCourse/timeline.tsx index 1b986ce..f400986 100644 --- a/src/components/dateCourse/timeline.tsx +++ b/src/components/dateCourse/timeline.tsx @@ -42,7 +42,7 @@ function Timeline({ end = false, title, time, address, price, tags, menu }: TTim
- {price} + {price}원
diff --git a/src/components/modal/dateCourseSearchFilterModal.tsx b/src/components/modal/dateCourseSearchFilterModal.tsx index 69a4c60..21a5895 100644 --- a/src/components/modal/dateCourseSearchFilterModal.tsx +++ b/src/components/modal/dateCourseSearchFilterModal.tsx @@ -1,5 +1,5 @@ // DateCourseSearchFilterModal.tsx -import { useMemo, useState } from 'react'; +import { useMemo } from 'react'; import { DateCourseQuestion } from '@/constants/dateCourseQuestion'; @@ -22,11 +22,53 @@ import useFilterStore from '@/store/useFilterStore'; type TProps = { onClose: () => void }; +// 공통 검증 함수: 특정 필드들만 받아 에러 배열 생성 +function computeErrors(f: { budget: any; dateDurationTime: any; mealTypes?: any[]; userPreferredKeywords?: any[]; startTime: any }): string[] { + const e: string[] = Array(7).fill(''); + + e[0] = + BudgetTimeValidation({ + budget: f.budget, + totalTime: f.dateDurationTime, + }) || ''; + + e[2] = + TotalTimeMealValidation({ + totalTime: f.dateDurationTime, + meal: f.mealTypes ?? [], + }) || ''; + + e[3] = + KeywordMealValidation({ + meal: f.mealTypes ?? [], + keywords: f.userPreferredKeywords ?? [], + }) || ''; + + e[5] = + KeywordGroupOverValidation({ + keywords: f.userPreferredKeywords ?? [], + }) || ''; + + e[6] = + MealTimeValidation({ + meal: f.mealTypes ?? [], + time: f.startTime, + totalTime: f.dateDurationTime, + }) || + DateTimeStartValidation({ + time: f.startTime, + totalTime: f.dateDurationTime, + }) || + ''; + + return e; +} + export default function DateCourseSearchFilterModal({ onClose }: TProps) { - const { setField, ...filters } = useFilterStore(); - const [errorMessages, setErrorMessages] = useState(Array(7).fill('')); + // ✅ 하나의 훅 호출로 필요한 값/액션 모두 가져오기 + const { budget, datePlaces, dateDurationTime, startTime, mealTypes, transportation, userPreferredKeywords, setField } = useFilterStore(); - const { budget, datePlaces, dateDurationTime, startTime, mealTypes, transportation, userPreferredKeywords } = useFilterStore(); + // API 데이터 (현재 필터 기준) const { data } = useGetCourse({ budget, datePlaces, @@ -38,80 +80,86 @@ export default function DateCourseSearchFilterModal({ onClose }: TProps) { size: 5, page: 1, }); + + // 질문 목록 (filterTitle 없는 항목 제외) const Questions = useMemo( () => (Array.isArray(DateCourseQuestion) ? DateCourseQuestion.slice(0, 7) : []) - .map((q) => ({ ...q, type: q.type as 'choice' | 'search' | 'time' | 'choices' | 'keyword' })) + .map((q) => ({ + ...q, + type: q.type as 'choice' | 'search' | 'time' | 'choices' | 'keyword', + })) .filter((q) => q.filterTitle !== ''), [], ); + // 인덱스 → 현재 값 매핑 const valueByIndex = (idx: number) => { switch (idx) { case 0: - return filters.budget; + return budget; case 1: - return filters.datePlaces; + return datePlaces; case 2: - return filters.dateDurationTime; + return dateDurationTime; case 3: - return filters.mealTypes; + return mealTypes; case 4: - return filters.transportation; + return transportation; case 5: - return filters.userPreferredKeywords; + return startTime; case 6: - return filters.startTime; + return userPreferredKeywords; default: return null; } }; - const runValidation = () => { - const errs = [...errorMessages]; - errs[0] = BudgetTimeValidation({ budget: filters.budget as any, totalTime: filters.dateDurationTime as any }) || ''; - errs[2] = TotalTimeMealValidation({ totalTime: filters.dateDurationTime as any, meal: filters.mealTypes ?? [] }) || ''; - errs[3] = KeywordMealValidation({ meal: filters.mealTypes ?? [], keywords: filters.userPreferredKeywords ?? [] }) || ''; - errs[5] = KeywordGroupOverValidation({ keywords: filters.userPreferredKeywords ?? [] }) || ''; - errs[6] = - MealTimeValidation({ meal: filters.mealTypes ?? [], time: filters.startTime as any, totalTime: filters.dateDurationTime as any }) || - DateTimeStartValidation({ time: filters.startTime as any, totalTime: filters.dateDurationTime as any }) || - ''; - setErrorMessages(errs); - return errs.every((e) => !e); - }; + // ✅ 에러는 상태로 들고 있지 않고, 항상 파생 계산 + const errorMessages = useMemo( + () => + computeErrors({ + budget, + dateDurationTime, + mealTypes, + userPreferredKeywords, + startTime, + }), + [budget, dateDurationTime, mealTypes, userPreferredKeywords, startTime], + ); - const updateByIndex = (idx: number, v: any) => { - const apply = () => { - switch (idx) { - case 0: - setField('budget', v ?? null); - break; - case 1: - setField('datePlaces', Array.isArray(v) ? v : []); - break; - case 2: - setField('dateDurationTime', v ?? null); - break; - case 3: - setField('mealTypes', Array.isArray(v) ? v : []); - break; - case 4: - setField('transportation', v ?? null); - break; - case 5: - setField('userPreferredKeywords', Array.isArray(v) ? v : []); - break; - case 6: - setField('startTime', v ?? null); - break; - } - }; - - apply(); - runValidation(); + // 값 갱신 (검증 호출 없음) + const updateByIndex = (idx: number, raw: any) => { + let v = raw; + + // 배열 필드는 타입 보정 + if ([1, 3, 6].includes(idx) && !Array.isArray(v)) v = []; + + switch (idx) { + case 0: + setField('budget', v ?? null); + break; + case 1: + setField('datePlaces', v); + break; + case 2: + setField('dateDurationTime', v ?? null); + break; + case 3: + setField('mealTypes', v); + break; + case 4: + setField('transportation', v ?? null); + break; + case 5: + setField('startTime', v ?? null); + break; + case 6: + setField('userPreferredKeywords', v); + break; + } }; - const number = 1234; + return (
@@ -122,7 +170,7 @@ export default function DateCourseSearchFilterModal({ onClose }: TProps) { subTitle={q.subTitle} options={q.options} value={valueByIndex(idx)} - onChange={(v) => updateByIndex(idx, v)} // ← 즉시 적용 + onChange={(v) => updateByIndex(idx, v)} type={q.type} apiRequestValue={q.apiRequestValue} errorMessage={errorMessages[idx] ?? ''} @@ -131,7 +179,7 @@ export default function DateCourseSearchFilterModal({ onClose }: TProps) {
diff --git a/src/components/modal/deleteBookmarkModal.tsx b/src/components/modal/deleteBookmarkModal.tsx index ed449cf..823fa9c 100644 --- a/src/components/modal/deleteBookmarkModal.tsx +++ b/src/components/modal/deleteBookmarkModal.tsx @@ -1,23 +1,36 @@ import { useEffect, useState } from 'react'; import { createPortal } from 'react-dom'; +import useBookmark from '@/hooks/course/useBookmark'; + type TDeleteBookmarkModal = { onClose: () => void; isOpen: boolean; changeState: (state: boolean) => void; + dateCourseId: number; }; -function DeleteBookmarkModal({ onClose, isOpen, changeState }: TDeleteBookmarkModal) { +function DeleteBookmarkModal({ onClose, dateCourseId, isOpen, changeState }: TDeleteBookmarkModal) { const [isVisible, setIsVisible] = useState(isOpen); - + const { useDeleteBookmark } = useBookmark(); + const { mutate: deleteBookmarkMutate } = useDeleteBookmark; useEffect(() => { setIsVisible(isOpen); }, [isOpen]); const handleDelete = () => { - // Logic to delete the bookmarked date course - changeState(false); - onClose(); + deleteBookmarkMutate( + { dateCourseId }, + { + onSuccess: () => { + changeState(false); + onClose(); + }, + onError: () => { + alert('북마크 삭제에 실패했습니다. 잠시후 다시 시도해주세요.'); + }, + }, + ); }; return createPortal( diff --git a/src/constants/dateCourseQuestion.ts b/src/constants/dateCourseQuestion.ts index 36c7603..3fcfda8 100644 --- a/src/constants/dateCourseQuestion.ts +++ b/src/constants/dateCourseQuestion.ts @@ -1,6 +1,6 @@ export const DateCourseQuestion = [ { - id: 1, + id: 0, filterTitle: '예산 범위', title: '오늘 데이트, 얼마나 쓰실 생각이세요?', subTitle: '(1인당)', @@ -10,7 +10,7 @@ export const DateCourseQuestion = [ type: 'choice', }, { - id: 2, + id: 1, title: '어디에서 만날까요?', subTitle: null, keyword: '만날 장소', @@ -20,7 +20,7 @@ export const DateCourseQuestion = [ filterTitle: '만날 장소', }, { - id: 3, + id: 2, title: '얼마나 함께할 예정인가요?', subTitle: '(1개만 선택 가능)', keyword: '데이트 시간', @@ -30,7 +30,7 @@ export const DateCourseQuestion = [ filterTitle: '데이트 시간', }, { - id: 4, + id: 3, title: '어떤 식사를 함께할 계획인가요?', subTitle: null, keyword: '식사 구성', @@ -40,7 +40,7 @@ export const DateCourseQuestion = [ filterTitle: '식사 구성', }, { - id: 5, + id: 4, title: '어떻게 이동하실 건가요?', subTitle: null, keyword: '이동 수단', @@ -50,7 +50,7 @@ export const DateCourseQuestion = [ filterTitle: '', }, { - id: 6, + id: 5, title: '오늘은 어떤 분위기의 데이트를 원하시나요?', subTitle: null, keyword: '데이트 키워드', @@ -60,7 +60,7 @@ export const DateCourseQuestion = [ filterTitle: '데이트 키워드', }, { - id: 7, + id: 6, title: '데이트 시작 시간을 알려주세요!', subTitle: '24:00 기준', keyword: null, diff --git a/src/hooks/course/useBookmark.ts b/src/hooks/course/useBookmark.ts index fa2ac64..636af87 100644 --- a/src/hooks/course/useBookmark.ts +++ b/src/hooks/course/useBookmark.ts @@ -1,9 +1,10 @@ import { useCoreMutation } from '../customQuery'; -import { deleteBookmark, postBookmark } from '@/api/course/course'; +import { deleteBookmark, postBookmark, postMakeBookmark } from '@/api/course/course'; export default function useBookmark() { const usePostBookmark = useCoreMutation(postBookmark); + const usePostMakeBookmark = useCoreMutation(postMakeBookmark); const useDeleteBookmark = useCoreMutation(deleteBookmark); - return { usePostBookmark, useDeleteBookmark }; + return { usePostBookmark, usePostMakeBookmark, useDeleteBookmark }; } diff --git a/src/pages/dateCourse/BookmarkedDateCourse.tsx b/src/pages/dateCourse/BookmarkedDateCourse.tsx index 7b86607..72b1352 100644 --- a/src/pages/dateCourse/BookmarkedDateCourse.tsx +++ b/src/pages/dateCourse/BookmarkedDateCourse.tsx @@ -44,7 +44,7 @@ function BookmarkedDateCourse() {
{data?.result.dateCourseList.map((course) => { - return ; + return ; })}
diff --git a/src/pages/dateCourse/FindDateCourse.tsx b/src/pages/dateCourse/FindDateCourse.tsx index 801692a..786be80 100644 --- a/src/pages/dateCourse/FindDateCourse.tsx +++ b/src/pages/dateCourse/FindDateCourse.tsx @@ -1,6 +1,6 @@ import { useState } from 'react'; -import useGetBookmarkedCourse from '@/hooks/course/useGetBookmarkedCourse'; +import useGetCourse from '@/hooks/course/useGetCourse'; import { MODAL_TYPES } from '@/components/common/modalProvider'; import Navigator from '@/components/common/navigator'; @@ -15,12 +15,12 @@ function FindDateCourse() { const [current, setCurrent] = useState(1); const { budget, datePlaces, dateDurationTime, startTime, mealTypes, transportation, userPreferredKeywords } = useFilterStore(); - const { data: courseData } = useGetBookmarkedCourse({ + const { data: courseData } = useGetCourse({ page: current, size: 5, budget, dateDurationTime, - datePlaces, + datePlaces: ['서울 종로구 인사동'], mealTypes, transportation, userPreferredKeywords, @@ -46,7 +46,7 @@ function FindDateCourse() { return ; })}
- + diff --git a/src/pages/dateCourse/MakeCourseResult.tsx b/src/pages/dateCourse/MakeCourseResult.tsx index c330da6..99b3517 100644 --- a/src/pages/dateCourse/MakeCourseResult.tsx +++ b/src/pages/dateCourse/MakeCourseResult.tsx @@ -1,8 +1,10 @@ import { useEffect, useState } from 'react'; -import { Navigate, useNavigate } from 'react-router-dom'; +import { useNavigate } from 'react-router-dom'; import type { TPostDateCourseResponse } from '@/types/dateCourse/dateCourse'; +import { toKSTISOString } from '@/utils/timeZoneChange'; + import { useCourse } from '@/hooks/course/useCourse'; import DateCourse from '@/components/dateCourse/dateCourse'; @@ -22,20 +24,26 @@ export default function MakeCourseResult() { const { mutate: makeCourseMutate, isPending } = useMakeCourse; useEffect(() => { + const date = new Date(startTime!); makeCourseMutate( { budget: budget!, dateDurationTime: dateDurationTime!, - datePlaces, + // datePlaces: datePlaces, + datePlaces: ['서울 종로구 인사동'], mealPlan: mealTypes, transportation: transportation!, userPreferredKeywords, - startTime: startTime!, + startTime: toKSTISOString(date), + excludedCourseSignatures: [], }, { onSuccess: (data) => { setCourseData(data); }, + onError: () => { + navigate('/makeCourse'); + }, }, ); }, []); @@ -43,9 +51,7 @@ export default function MakeCourseResult() { if (isPending) { return ; } - if (!courseData) { - return ; - } + return (
@@ -54,7 +60,11 @@ export default function MakeCourseResult() {
- + {courseData?.result?.datePlaces && courseData?.result?.datePlaces?.length > 0 ? ( + + ) : ( +
+ )}
diff --git a/src/pages/dateCourse/MakeCourseStep.tsx b/src/pages/dateCourse/MakeCourseStep.tsx index 3072e89..6e2a64f 100644 --- a/src/pages/dateCourse/MakeCourseStep.tsx +++ b/src/pages/dateCourse/MakeCourseStep.tsx @@ -157,7 +157,9 @@ export default function MakeCourseStep() { } setErrorMessage(msg); }, [currentStep, budget, dateDurationTime, mealTypes, userPreferredKeywords, startTime]); - + useEffect(() => { + console.log(budget, datePlaces, dateDurationTime, mealTypes, transportation, userPreferredKeywords, startTime); + }, [budget, dateDurationTime, mealTypes, userPreferredKeywords, startTime, transportation]); if (!question) return
질문을 불러올 수 없습니다.
; return ( diff --git a/src/types/dateCourse/dateCourse.ts b/src/types/dateCourse/dateCourse.ts index a1bef47..9a8acc2 100644 --- a/src/types/dateCourse/dateCourse.ts +++ b/src/types/dateCourse/dateCourse.ts @@ -7,16 +7,16 @@ export type TTimeline = { title?: string; time: string; address?: string; - price?: string; + price?: number; tags?: string[]; menu?: string; }; export type TInfo = { - cashTag: string; - locationTag: string; - timeTag: string; - MealTag: string; - keywordTags: string[]; + cashTag?: string; + locationTag?: string[]; + timeTag?: string; + MealTag?: string[]; + keywordTags?: string[]; }; export type TTag = { id: number; @@ -34,7 +34,7 @@ export type TDateKeyword = { }; export type TKeywordButtonProps = { - tag: string; + tag?: string; selected?: boolean; onClick?: () => void; isButton?: boolean; @@ -94,8 +94,7 @@ export type TRegion = { createdAt: string; updatedAt: string; }; - -export type TPostDateCourseRequest = { +export type TDateCourseSearchCondInfo = { budget: string; datePlaces: string[]; dateDurationTime: string; @@ -104,14 +103,20 @@ export type TPostDateCourseRequest = { userPreferredKeywords: string[]; startTime: string; }; +export type TPostDateCourseRequest = TDateCourseSearchCondInfo & { + excludedCourseSignatures: string[]; +}; export type TPostDateCourseResponse = TCommonResponse; export type TDatePlaces = { name: string; + datePlaceId: number; + startTime: string; + endTime: string; image: string; tel: string; - averagePrive: number; + averagePrice: number; information: string; latitude: number; longitude: number; @@ -120,10 +125,14 @@ export type TDatePlaces = { placeType: string; }; export type TDateCourse = { - dateCourseId: number; name: string; + dateCourseId?: number; datePlaces: TDatePlaces[]; + dateCourseSearchCondInfo: TDateCourseSearchCondInfo; + isBookmarked: boolean; + signature: string; }; + export type TPostBookmarkRequest = { dateCourseId: number; }; @@ -132,6 +141,15 @@ export type TPostBookmarkResponse = TCommonResponse<{ dateCourseId: number; }>; +export type TPostMakeBookmarkRequest = { + datePlaceIds: number[]; + name: string; +}; + +export type TPostMakeBookmarkResponse = TCommonResponse<{ + dateCourseId: number; +}>; + export type TDeleteBookmarkRequest = { dateCourseId: number; }; @@ -151,6 +169,7 @@ export type TGetDateCourseResponse = TCommonResponse<{ currentPage: number; currentSize: number; hasNextPage: boolean; + totalCount: number; }>; export type TGetBookmarkedDateCourseRequest = TCourseFilter & { diff --git a/src/utils/dateCourseValidation.tsx b/src/utils/dateCourseValidation.tsx index fbfc86c..4e19da2 100644 --- a/src/utils/dateCourseValidation.tsx +++ b/src/utils/dateCourseValidation.tsx @@ -66,7 +66,6 @@ export function MealTimeValidation({ meal, time, totalTime }: { meal: string[]; // 아무것도 안겹치면 첫 번째 식사를 기준으로 안내 const first = meal[0]; - console.log(first); const [mealStartStr, mealEndStr] = mealTimeRanges[first]; return `선택하신 시간에는 ${mealTimeKorean[first]} 식사를 하기 어려워요. (가능 시간: ${mealStartStr}~${mealEndStr})`; diff --git a/src/utils/timeZoneChange.ts b/src/utils/timeZoneChange.ts new file mode 100644 index 0000000..2dd0d92 --- /dev/null +++ b/src/utils/timeZoneChange.ts @@ -0,0 +1,24 @@ +export function toKSTISOString(date: Date, withOffset = false) { + const pad = (n: number) => String(n).padStart(2, '0'); + + // 현재 로컬 시간이 UTC+9인지 보장하기 위해 UTC 기준에서 9시간 더해줌 + const kstDate = new Date(date.getTime() + 9 * 60 * 60 * 1000); + + const result = + kstDate.getFullYear() + + '-' + + pad(kstDate.getMonth() + 1) + + '-' + + pad(kstDate.getDate()) + + 'T' + + pad(kstDate.getHours()) + + ':' + + pad(kstDate.getMinutes()) + + ':' + + pad(kstDate.getSeconds()) + + '.' + + String(kstDate.getMilliseconds()).padStart(3, '0'); + + // withOffset = true → "+09:00" 붙이기 + return withOffset ? `${result}+09:00` : result; +} From 967a9504f2e4917b627c50d0e2d039a6e5584be2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=97=B0=EC=A7=84?= Date: Fri, 15 Aug 2025 06:54:00 +0900 Subject: [PATCH 04/17] =?UTF-8?q?feat:=20=EB=B0=B1=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + src/api/course/course.ts | 18 +++++------ .../dateCourseSearchFilterOption.tsx | 1 - src/components/home/level.tsx | 3 +- .../modal/dateCourseSearchFilterModal.tsx | 16 +++++++--- src/constants/level.ts | 30 +++++++++++++++++++ src/pages/dateCourse/CoursePage.tsx | 8 +++-- yarn.lock | 12 ++++++++ 8 files changed, 71 insertions(+), 18 deletions(-) create mode 100644 src/constants/level.ts diff --git a/package.json b/package.json index b0c2bc5..3949889 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "lodash.throttle": "^4.1.1", "path": "^0.12.7", "prettier": "^3.5.3", + "qs": "^6.14.0", "react": "^19.1.0", "react-chartjs-2": "^5.3.0", "react-dom": "^19.1.0", diff --git a/src/api/course/course.ts b/src/api/course/course.ts index 457a65c..3cd03b8 100644 --- a/src/api/course/course.ts +++ b/src/api/course/course.ts @@ -97,16 +97,14 @@ export const getBookmarkedDateCourse = async ({ page, size, }: TGetBookmarkedDateCourseRequest): Promise => { - const { data } = await axiosInstance.get('/api/v1/date-courses/search', { - params: { - page, - size, - budget, - datePlaces, - mealTypes, - transportation, - userPreferredKeywords, - }, + const { data } = await axiosInstance.post('/api/v1/date-courses/bookmarks/search', { + page, + size, + budget, + datePlaces, + mealTypes, + transportation, + userPreferredKeywords, }); return data; }; diff --git a/src/components/dateCourse/dateCourseSearchFilterOption.tsx b/src/components/dateCourse/dateCourseSearchFilterOption.tsx index 8aadc4d..225fd67 100644 --- a/src/components/dateCourse/dateCourseSearchFilterOption.tsx +++ b/src/components/dateCourse/dateCourseSearchFilterOption.tsx @@ -95,7 +95,6 @@ export default function DateCourseSearchFilterOption({ isSelected={value === apiValue} onClick={() => { onChange(apiValue!); - console.log('click'); }} /> ); diff --git a/src/components/home/level.tsx b/src/components/home/level.tsx index 0ea8d0a..d057f19 100644 --- a/src/components/home/level.tsx +++ b/src/components/home/level.tsx @@ -1,6 +1,7 @@ import { useEffect, useState } from 'react'; import type { IGradeInfo } from '@/types/home/level'; +import { getProgressToNextGrade } from '@/constants/level'; import MainCard from '@/components/home/mainCard'; @@ -10,7 +11,7 @@ function Level({ grade, nextRequiredPoint }: IGradeInfo) { const [percentage, setPercentage] = useState(0); useEffect(() => { - setPercentage(100 - nextRequiredPoint); + setPercentage(getProgressToNextGrade(grade, nextRequiredPoint)); }, [nextRequiredPoint]); return ( diff --git a/src/components/modal/dateCourseSearchFilterModal.tsx b/src/components/modal/dateCourseSearchFilterModal.tsx index 21a5895..402949c 100644 --- a/src/components/modal/dateCourseSearchFilterModal.tsx +++ b/src/components/modal/dateCourseSearchFilterModal.tsx @@ -1,5 +1,6 @@ // DateCourseSearchFilterModal.tsx -import { useMemo } from 'react'; +import { useEffect, useMemo, useState } from 'react'; +import { useLocation } from 'react-router-dom'; import { DateCourseQuestion } from '@/constants/dateCourseQuestion'; @@ -22,7 +23,6 @@ import useFilterStore from '@/store/useFilterStore'; type TProps = { onClose: () => void }; -// 공통 검증 함수: 특정 필드들만 받아 에러 배열 생성 function computeErrors(f: { budget: any; dateDurationTime: any; mealTypes?: any[]; userPreferredKeywords?: any[]; startTime: any }): string[] { const e: string[] = Array(7).fill(''); @@ -65,9 +65,17 @@ function computeErrors(f: { budget: any; dateDurationTime: any; mealTypes?: any[ } export default function DateCourseSearchFilterModal({ onClose }: TProps) { - // ✅ 하나의 훅 호출로 필요한 값/액션 모두 가져오기 const { budget, datePlaces, dateDurationTime, startTime, mealTypes, transportation, userPreferredKeywords, setField } = useFilterStore(); - + const [bookmarkedValue, setBookmarkedValue] = useState(false); + + const location = useLocation(); + useEffect(() => { + if (location.pathname === '/bookmarkedCourse') { + setBookmarkedValue(true); + } else { + setBookmarkedValue(false); + } + }, [location]); // API 데이터 (현재 필터 기준) const { data } = useGetCourse({ budget, diff --git a/src/constants/level.ts b/src/constants/level.ts new file mode 100644 index 0000000..e4d1a93 --- /dev/null +++ b/src/constants/level.ts @@ -0,0 +1,30 @@ +type TGradeInfo = { + name: string; + point: number; // 해당 등급 시작 포인트 +}; + +const gradeTable: TGradeInfo[] = [ + { name: 'FLIRT', point: 0 }, + { name: 'EXPLORER', point: 50 }, + { name: 'SEEKER', point: 150 }, + { name: 'NAVIGATOR', point: 300 }, + { name: 'JOURNEYMAN', point: 500 }, + { name: 'TRAILBLAZER', point: 800 }, + { name: 'TIMEKEEPER', point: 1200 }, + { name: 'ROMANTIC NOMAD', point: 1700 }, + { name: 'MASTER OF MOMENTS', point: 2300 }, + { name: 'WITHTIME', point: 3000 }, +]; + +export function getProgressToNextGrade(grade: string, currentPoint: number): number { + const currentIndex = gradeTable.findIndex((g) => g.name === grade); + if (currentIndex === -1) throw new Error(`Unknown grade: ${grade}`); + + if (currentIndex === gradeTable.length - 1) return 100; + + const startPoint = gradeTable[currentIndex].point; + const nextPoint = gradeTable[currentIndex + 1].point; + + const progress = ((nextPoint - startPoint - currentPoint) / (nextPoint - startPoint)) * 100; + return Math.max(0, Math.min(progress, 100)); +} diff --git a/src/pages/dateCourse/CoursePage.tsx b/src/pages/dateCourse/CoursePage.tsx index 875206d..65e86a8 100644 --- a/src/pages/dateCourse/CoursePage.tsx +++ b/src/pages/dateCourse/CoursePage.tsx @@ -2,6 +2,7 @@ import { useState } from 'react'; import { useNavigate } from 'react-router-dom'; import useGetBookmarkedCourse from '@/hooks/course/useGetBookmarkedCourse'; +import { useUserGrade } from '@/hooks/home/useUserGrade'; import { MODAL_TYPES } from '@/components/common/modalProvider'; import Navigator from '@/components/common/navigator'; @@ -18,6 +19,7 @@ export default function Course() { const [current, setCurrent] = useState(1); const { budget, datePlaces, dateDurationTime, startTime, mealTypes, transportation, userPreferredKeywords } = useFilterStore(); + // 수정 예정 const { data } = useGetBookmarkedCourse({ page: current, size: 5, @@ -29,7 +31,7 @@ export default function Course() { userPreferredKeywords, startTime, }); - + const { data: gradeData } = useUserGrade(); return (
@@ -49,7 +51,9 @@ export default function Course() {
-
Madeleine 님만의 데이트 코스
+
+ {gradeData?.result.username} 님만의 데이트 코스 +
navigate('/bookmarkedCourse')} diff --git a/yarn.lock b/yarn.lock index 809543e..c7ae6b6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1584,6 +1584,11 @@ dependencies: undici-types "~7.10.0" +"@types/qs@^6.14.0": + version "6.14.0" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.14.0.tgz#d8b60cecf62f2db0fb68e5e006077b9178b85de5" + integrity sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ== + "@types/react-dom@^19.1.2": version "19.1.6" resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.6.tgz" @@ -4094,6 +4099,13 @@ punycode@^2.1.0: resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz" integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== +qs@^6.14.0: + version "6.14.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.14.0.tgz#c63fa40680d2c5c941412a0e899c89af60c0a930" + integrity sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w== + dependencies: + side-channel "^1.1.0" + queue-microtask@^1.2.2: version "1.2.3" resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz" From 4ac40a8d46a0471a5fe3b7cb984c71ea43306318 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=97=B0=EC=A7=84?= Date: Fri, 15 Aug 2025 18:17:32 +0900 Subject: [PATCH 05/17] =?UTF-8?q?feat:=20=EB=8D=B0=EC=9D=B4=ED=8A=B8=20?= =?UTF-8?q?=EC=BD=94=EC=8A=A4=20=EC=83=9D=EC=84=B1=20=EC=97=B0=EA=B2=B0=20?= =?UTF-8?q?=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/course/course.ts | 4 +- src/components/dateCourse/dateCourse.tsx | 21 ++----- src/components/dateCourse/info.tsx | 27 ++++++++- src/components/dateCourse/timeline.tsx | 29 +++++---- src/constants/dateCourseQuestion.ts | 21 +++++++ src/constants/level.ts | 4 +- src/pages/dateCourse/FindDateCourse.tsx | 2 +- src/pages/dateCourse/MakeCourseResult.tsx | 42 ++++++------- src/pages/dateCourse/MakeCourseStep.tsx | 73 ++++++++++++++++------- src/store/useDateCourseResultStore.ts | 33 ++++++++++ src/types/dateCourse/dateCourse.ts | 54 ++++++++++++----- src/utils/appendSignature.ts | 49 +++++++++++++++ src/utils/timeZoneChange.ts | 24 -------- 13 files changed, 265 insertions(+), 118 deletions(-) create mode 100644 src/store/useDateCourseResultStore.ts create mode 100644 src/utils/appendSignature.ts delete mode 100644 src/utils/timeZoneChange.ts diff --git a/src/api/course/course.ts b/src/api/course/course.ts index 3cd03b8..49ca2f3 100644 --- a/src/api/course/course.ts +++ b/src/api/course/course.ts @@ -31,7 +31,7 @@ export const searchRegion = async ({ keyword }: TSearchRegionValues): Promise(isBookmarked); const [dateCourseID, setDateCourseID] = useState(dateCourseId); const moreRef = useRef(null); const { usePostBookmark, usePostMakeBookmark } = useBookmark(); @@ -67,6 +67,7 @@ function DateCourse({ defaultOpen = false, name, make, dateCourseId, isBookmarke document.addEventListener('mousedown', handleClickOutside); return () => document.removeEventListener('mousedown', handleClickOutside); }, [openEdit]); + const lastEndTime = datePlaces[datePlaces.length - 1]?.endTime; return (
@@ -99,19 +100,9 @@ function DateCourse({ defaultOpen = false, name, make, dateCourseId, isBookmarke
{datePlaces.map((place, idx) => { - return ( - - ); + return ; })} - +
@@ -119,7 +110,7 @@ function DateCourse({ defaultOpen = false, name, make, dateCourseId, isBookmarke cashTag={dateCourseSearchCondInfo?.budget} locationTag={dateCourseSearchCondInfo?.datePlaces} timeTag={dateCourseSearchCondInfo?.dateDurationTime} - MealTag={dateCourseSearchCondInfo?.mealPlan} + MealTag={dateCourseSearchCondInfo?.mealTypes} keywordTags={dateCourseSearchCondInfo?.userPreferredKeywords} />
diff --git a/src/components/dateCourse/info.tsx b/src/components/dateCourse/info.tsx index a0bb6ec..87b2556 100644 --- a/src/components/dateCourse/info.tsx +++ b/src/components/dateCourse/info.tsx @@ -1,4 +1,5 @@ import type { TInfo } from '@/types/dateCourse/dateCourse'; +import { Budget, Meal, TotalTime } from '@/constants/dateCourseQuestion'; import InfoElement from './infoElement'; @@ -9,20 +10,40 @@ import Location from '@/assets/icons/Location_Blank.svg?react'; import Spoon from '@/assets/icons/spoon_Blank.svg?react'; export default function Info({ cashTag, locationTag, timeTag, MealTag, keywordTags }: TInfo) { + type TBudgetKey = keyof typeof Budget; + type TTotalTimeKey = keyof typeof TotalTime; + type TMealKey = keyof typeof Meal; + function isBudgetKey(v: string): v is TBudgetKey { + return Object.prototype.hasOwnProperty.call(Budget, v); + } + function isTotalTimeKey(v: string): v is TTotalTimeKey { + return Object.prototype.hasOwnProperty.call(TotalTime, v); + } + + function isMealKey(v: string): v is TMealKey { + return Object.prototype.hasOwnProperty.call(Meal, v); + } + + const label = isBudgetKey(cashTag) ? Budget[cashTag] : '알 수 없음'; + const totalTime = isTotalTimeKey(timeTag) ? TotalTime[timeTag] : '알 수 없음'; + const meals = Array.isArray(MealTag) ? MealTag.filter(isMealKey).map((tag) => Meal[tag]) : []; + return (
- + - + - + + + diff --git a/src/components/dateCourse/timeline.tsx b/src/components/dateCourse/timeline.tsx index f400986..4bc70d0 100644 --- a/src/components/dateCourse/timeline.tsx +++ b/src/components/dateCourse/timeline.tsx @@ -10,39 +10,46 @@ import Cash from '@/assets/icons/cash_Blank.svg?react'; import CheckSuccess from '@/assets/icons/Check-Success-Blank.svg?react'; import Location from '@/assets/icons/Location_Blank.svg?react'; -function Timeline({ end = false, title, time, address, price, tags, menu }: TTimeline) { +function Timeline({ end = false, image, name, tags, roadNameAddress, averagePrice, time, signatureDish }: TTimeline) { const [open, setOpen] = useState(false); return (
(end ? undefined : setOpen(!open))}> -
{time}
+
+ {time.split(':')[0]}:{time.split(':')[1]} +
-
{end ? 'End' : title}
+
{end ? 'End' : name}
{!end && }
{open && (
-
-
-
WithTime Pick
- -
- +
+ {signatureDish && ( +
+
+
WithTime Pick
+ +
+ +
+ )} + {image && }
- {address} + {roadNameAddress}
- {price}원 + {averagePrice}원
diff --git a/src/constants/dateCourseQuestion.ts b/src/constants/dateCourseQuestion.ts index 3fcfda8..7ed5686 100644 --- a/src/constants/dateCourseQuestion.ts +++ b/src/constants/dateCourseQuestion.ts @@ -70,3 +70,24 @@ export const DateCourseQuestion = [ filterTitle: '만날 시간', }, ]; + +export enum Budget { + UNDER_10K = '1만원 이하', + FROM_10K_TO_20K = '1-2만원', + FROM_20K_TO_30K = '2-3만원', + OVER_30K = '3만원 이상', +} + +export enum TotalTime { + ONETOTWO = '1-2시간', + TWOTOTHREE = '2-3시간', + THREETOFOUR = '3-4시간', + HALFDAY = '반나절', + ALLDAY = '하루 종일', +} + +export enum Meal { + BREAKFAST = '아침', + LUNCH = '점심', + DINNER = '저녁', +} diff --git a/src/constants/level.ts b/src/constants/level.ts index e4d1a93..8a440cb 100644 --- a/src/constants/level.ts +++ b/src/constants/level.ts @@ -11,8 +11,8 @@ const gradeTable: TGradeInfo[] = [ { name: 'JOURNEYMAN', point: 500 }, { name: 'TRAILBLAZER', point: 800 }, { name: 'TIMEKEEPER', point: 1200 }, - { name: 'ROMANTIC NOMAD', point: 1700 }, - { name: 'MASTER OF MOMENTS', point: 2300 }, + { name: 'ROMANTIC_NOMAD', point: 1700 }, + { name: 'MASTER_OF_MOMENTS', point: 2300 }, { name: 'WITHTIME', point: 3000 }, ]; diff --git a/src/pages/dateCourse/FindDateCourse.tsx b/src/pages/dateCourse/FindDateCourse.tsx index 786be80..7784132 100644 --- a/src/pages/dateCourse/FindDateCourse.tsx +++ b/src/pages/dateCourse/FindDateCourse.tsx @@ -20,7 +20,7 @@ function FindDateCourse() { size: 5, budget, dateDurationTime, - datePlaces: ['서울 종로구 인사동'], + datePlaces: datePlaces, mealTypes, transportation, userPreferredKeywords, diff --git a/src/pages/dateCourse/MakeCourseResult.tsx b/src/pages/dateCourse/MakeCourseResult.tsx index 99b3517..abb320f 100644 --- a/src/pages/dateCourse/MakeCourseResult.tsx +++ b/src/pages/dateCourse/MakeCourseResult.tsx @@ -1,11 +1,9 @@ -import { useEffect, useState } from 'react'; import { useNavigate } from 'react-router-dom'; -import type { TPostDateCourseResponse } from '@/types/dateCourse/dateCourse'; - -import { toKSTISOString } from '@/utils/timeZoneChange'; +import { SigStorage } from '@/utils/appendSignature'; import { useCourse } from '@/hooks/course/useCourse'; +import { useUserGrade } from '@/hooks/home/useUserGrade'; import DateCourse from '@/components/dateCourse/dateCourse'; import DateCourseLoading from '@/components/dateCourse/dateCourseLoading'; @@ -14,62 +12,58 @@ import Button from '../../components/common/Button'; import Reload from '@/assets/icons/arrow_spin.svg?react'; import Logo from '@/assets/withTimeLogo//logo_Blank.svg?react'; +import useDateCourseResultStore from '@/store/useDateCourseResultStore'; import useFilterStore from '@/store/useFilterStore'; export default function MakeCourseResult() { const navigate = useNavigate(); - const [courseData, setCourseData] = useState(); + const { setAll, ...courseData } = useDateCourseResultStore(); const { useMakeCourse } = useCourse(); - const { budget, datePlaces, dateDurationTime, startTime, mealTypes, transportation, userPreferredKeywords } = useFilterStore(); + const { budget, datePlaces, dateDurationTime, mealTypes, transportation, userPreferredKeywords, startTime } = useFilterStore(); const { mutate: makeCourseMutate, isPending } = useMakeCourse; + const { data: gradeData } = useUserGrade(); - useEffect(() => { - const date = new Date(startTime!); + const handleSubmit = () => { makeCourseMutate( { budget: budget!, dateDurationTime: dateDurationTime!, - // datePlaces: datePlaces, - datePlaces: ['서울 종로구 인사동'], - mealPlan: mealTypes, + datePlaces: datePlaces, + mealTypes: mealTypes, transportation: transportation!, userPreferredKeywords, - startTime: toKSTISOString(date), - excludedCourseSignatures: [], + startTime: startTime!, + excludedCourseSignatures: JSON.parse(localStorage.getItem('signature') ?? '[]'), }, { onSuccess: (data) => { - setCourseData(data); + SigStorage.append(data.result.signature); + setAll(data.result); + navigate('/makeCourse/result'); }, onError: () => { navigate('/makeCourse'); }, }, ); - }, []); - + }; if (isPending) { return ; } - return (
-
Madeleine 님만의 데이트 코스
+
{gradeData?.result.username} 님만의 데이트 코스
- {courseData?.result?.datePlaces && courseData?.result?.datePlaces?.length > 0 ? ( - - ) : ( -
- )} + {courseData.datePlaces && courseData.datePlaces?.length > 0 ? :
}
+ {currentStep === TOTAL_QUESTIONS - 1 ? ( + + ) : ( + + )}
diff --git a/src/store/useDateCourseResultStore.ts b/src/store/useDateCourseResultStore.ts new file mode 100644 index 0000000..445fbac --- /dev/null +++ b/src/store/useDateCourseResultStore.ts @@ -0,0 +1,33 @@ +import { create } from 'zustand'; + +import type { TDateCourseSearchCondInfo, TDatePlaces } from '@/types/dateCourse/dateCourse'; + +type TDataState = { + name: string; + datePlaces: TDatePlaces[]; + dateCourseSearchCondInfo: TDateCourseSearchCondInfo; + isBookmarked: boolean | null; + signature: string; +}; + +interface IDateCourseResultStoreState extends TDataState { + resetDateCourseResultStore: () => void; + setAll: (payload: TDataState) => void; +} + +const INITIAL_DATA: TDataState = { + name: '', + datePlaces: [], + dateCourseSearchCondInfo: {} as TDateCourseSearchCondInfo, + isBookmarked: null, + signature: '', +}; + +const useDateCourseResultStore = create((set) => ({ + ...INITIAL_DATA, + + resetDateCourseResultStore: () => set(INITIAL_DATA), + setAll: (payload) => set((prev) => ({ ...prev, ...payload })), +})); + +export default useDateCourseResultStore; diff --git a/src/types/dateCourse/dateCourse.ts b/src/types/dateCourse/dateCourse.ts index 9a8acc2..cf5e0d4 100644 --- a/src/types/dateCourse/dateCourse.ts +++ b/src/types/dateCourse/dateCourse.ts @@ -2,21 +2,12 @@ import type { Dispatch, SetStateAction } from 'react'; import type { TCommonResponse } from '@/types/common/common'; -export type TTimeline = { - end?: boolean; - title?: string; - time: string; - address?: string; - price?: number; - tags?: string[]; - menu?: string; -}; export type TInfo = { - cashTag?: string; - locationTag?: string[]; - timeTag?: string; - MealTag?: string[]; - keywordTags?: string[]; + cashTag: string; + locationTag: string[]; + timeTag: string; + MealTag: string[]; + keywordTags: string[]; }; export type TTag = { id: number; @@ -24,6 +15,13 @@ export type TTag = { code: string; }; +type TSignatureDish = { + ItemId: number; + imageUrl: string; + name: string; + price: string; +}; + export type TTags = TTag[]; export type TDateKeyword = { @@ -98,7 +96,7 @@ export type TDateCourseSearchCondInfo = { budget: string; datePlaces: string[]; dateDurationTime: string; - mealPlan: string[]; + mealTypes: string[]; transportation: string; userPreferredKeywords: string[]; startTime: string; @@ -123,13 +121,37 @@ export type TDatePlaces = { roadNameAddress: string; lotNumberAddress: string; placeType: string; + signatureDish: TSignatureDish | null; }; + +export type TTimeline = { + name?: string; + dateCourseId?: number; + datePlaceId?: number; + startTime?: string; + endTime?: string; + image?: string | null; + tel?: string; + averagePrice?: number; + information?: string; + latitude?: number; + longitude?: number; + roadNameAddress?: string; + lotNumberAddress?: string; + placeType?: string; + signatureDish?: TSignatureDish | null; + defaultOpen?: boolean; + time: string; + end?: boolean; + tags?: string[]; +}; + export type TDateCourse = { name: string; dateCourseId?: number; datePlaces: TDatePlaces[]; dateCourseSearchCondInfo: TDateCourseSearchCondInfo; - isBookmarked: boolean; + isBookmarked: boolean | null; signature: string; }; diff --git a/src/utils/appendSignature.ts b/src/utils/appendSignature.ts new file mode 100644 index 0000000..d259ad9 --- /dev/null +++ b/src/utils/appendSignature.ts @@ -0,0 +1,49 @@ +export const SigStorage = { + key: 'signature', + + // 안전 파서: 문자열로 저장돼 있던 과거 값도 배열로 마이그레이션 + _parse(raw: string | null): string[] { + if (raw == null) return []; + try { + const parsed = JSON.parse(raw); + return Array.isArray(parsed) ? parsed : [String(parsed)]; + } catch { + return [raw]; // JSON이 아니면 과거 단일 문자열로 간주 + } + }, + + get(): string[] { + try { + return this._parse(localStorage.getItem(this.key)); + } catch { + return []; + } + }, + + append(sig: string) { + if (!sig) return; // 빈값 방지 + try { + const list = this.get(); + list.push(sig); + localStorage.setItem(this.key, JSON.stringify(list)); + // 디버그 확인 + console.log('[SigStorage] after append:', localStorage.getItem(this.key)); + } catch (e) { + console.error('[SigStorage] append failed:', e); + } + }, + + appendUnique(sig: string) { + if (!sig) return; + try { + const list = this.get(); + if (!list.includes(sig)) { + list.push(sig); + localStorage.setItem(this.key, JSON.stringify(list)); + } + console.log('[SigStorage] after appendUnique:', localStorage.getItem(this.key)); + } catch (e) { + console.error('[SigStorage] appendUnique failed:', e); + } + }, +}; diff --git a/src/utils/timeZoneChange.ts b/src/utils/timeZoneChange.ts deleted file mode 100644 index 2dd0d92..0000000 --- a/src/utils/timeZoneChange.ts +++ /dev/null @@ -1,24 +0,0 @@ -export function toKSTISOString(date: Date, withOffset = false) { - const pad = (n: number) => String(n).padStart(2, '0'); - - // 현재 로컬 시간이 UTC+9인지 보장하기 위해 UTC 기준에서 9시간 더해줌 - const kstDate = new Date(date.getTime() + 9 * 60 * 60 * 1000); - - const result = - kstDate.getFullYear() + - '-' + - pad(kstDate.getMonth() + 1) + - '-' + - pad(kstDate.getDate()) + - 'T' + - pad(kstDate.getHours()) + - ':' + - pad(kstDate.getMinutes()) + - ':' + - pad(kstDate.getSeconds()) + - '.' + - String(kstDate.getMilliseconds()).padStart(3, '0'); - - // withOffset = true → "+09:00" 붙이기 - return withOffset ? `${result}+09:00` : result; -} From b6c463566e6839c2d560e4a53acb4a10cd028309 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=97=B0=EC=A7=84?= Date: Fri, 15 Aug 2025 18:28:59 +0900 Subject: [PATCH 06/17] =?UTF-8?q?feat:=20=EA=B8=B0=ED=9A=8D=20=EC=83=81=20?= =?UTF-8?q?=EC=97=86=EC=96=B4=EC=A7=84=20=ED=8E=98=EC=9D=B4=EC=A7=80=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/modal/dateCourseSearchFilterModal.tsx | 2 +- src/pages/dateCourse/CoursePage.tsx | 8 -------- src/pages/dateCourse/FindDateCourse.tsx | 9 +++++++-- src/pages/dateCourse/MakeCourseResult.tsx | 10 +++++++++- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/components/modal/dateCourseSearchFilterModal.tsx b/src/components/modal/dateCourseSearchFilterModal.tsx index 402949c..04729fd 100644 --- a/src/components/modal/dateCourseSearchFilterModal.tsx +++ b/src/components/modal/dateCourseSearchFilterModal.tsx @@ -170,7 +170,7 @@ export default function DateCourseSearchFilterModal({ onClose }: TProps) { return ( -
+
{Questions.map((q, idx) => (
-
navigate('/bookmarkedCourse')} - className="hover:cursor-pointer select-none px-[16px] py-[8px] text-body2 rounding-16 flex gap-[4px] w-fit rounding-16 border-[1px] border-default-gray-700 text-default-gray-700" - > - - 저장된 코스 보기 -
openModal({ modalType: MODAL_TYPES.DateCourseSearchFilterModal })} diff --git a/src/pages/dateCourse/FindDateCourse.tsx b/src/pages/dateCourse/FindDateCourse.tsx index 7784132..75594fc 100644 --- a/src/pages/dateCourse/FindDateCourse.tsx +++ b/src/pages/dateCourse/FindDateCourse.tsx @@ -1,7 +1,9 @@ import { useState } from 'react'; +import { useNavigate } from 'react-router-dom'; import useGetCourse from '@/hooks/course/useGetCourse'; +import GraySvgButton from '@/components/common/graySvgButton'; import { MODAL_TYPES } from '@/components/common/modalProvider'; import Navigator from '@/components/common/navigator'; import DateCourse from '@/components/dateCourse/dateCourse'; @@ -13,7 +15,7 @@ import useModalStore from '@/store/useModalStore'; function FindDateCourse() { const { openModal } = useModalStore(); const [current, setCurrent] = useState(1); - + const navigate = useNavigate(); const { budget, datePlaces, dateDurationTime, startTime, mealTypes, transportation, userPreferredKeywords } = useFilterStore(); const { data: courseData } = useGetCourse({ page: current, @@ -29,7 +31,10 @@ function FindDateCourse() { return (
-
+
+
+ navigate('/dateCourse')} /> +
직접 데이트 코스 찾아보기
diff --git a/src/pages/dateCourse/MakeCourseResult.tsx b/src/pages/dateCourse/MakeCourseResult.tsx index abb320f..a7ad937 100644 --- a/src/pages/dateCourse/MakeCourseResult.tsx +++ b/src/pages/dateCourse/MakeCourseResult.tsx @@ -58,7 +58,15 @@ export default function MakeCourseResult() {
- {courseData.datePlaces && courseData.datePlaces?.length > 0 ? :
} + {courseData.datePlaces && courseData.datePlaces?.length > 0 ? ( + + ) : ( +
+ 입력하신 조건을 만족하는 데이트 코스 제작에 실패하였습니다. +
+ 다른 조건으로 재시도 해보세요 +
+ )}
{pages.map((page) => ( ))} -
diff --git a/src/components/dateCourse/dateCourse.tsx b/src/components/dateCourse/dateCourse.tsx index 4640fdf..bd782c9 100644 --- a/src/components/dateCourse/dateCourse.tsx +++ b/src/components/dateCourse/dateCourse.tsx @@ -32,6 +32,11 @@ function DateCourse({ defaultOpen = false, name, make, dateCourseId, isBookmarke const { mutate: postMakeBookmark } = usePostMakeBookmark; const ids = (datePlaces ?? []).map((p) => p.datePlaceId); + useEffect(() => { + setBookmarked(isBookmarked); + setDateCourseID(dateCourseId); + }, [isBookmarked, dateCourseId]); + const clickBookmark = () => { if (bookmarked) { setOpenModal(true); @@ -52,6 +57,10 @@ function DateCourse({ defaultOpen = false, name, make, dateCourseId, isBookmarke }, ); } else { + if (dateCourseID == null) { + console.error('dateCourseId가 없어 북마크를 생성할 수 없습니다'); + return; + } postBookmark({ dateCourseId: dateCourseID!, }); diff --git a/src/components/dateCourse/dateCourseLoading.tsx b/src/components/dateCourse/dateCourseLoading.tsx index 698afe1..2f63009 100644 --- a/src/components/dateCourse/dateCourseLoading.tsx +++ b/src/components/dateCourse/dateCourseLoading.tsx @@ -1,11 +1,14 @@ +import { useUserGrade } from '@/hooks/home/useUserGrade'; + import LoadingLogo from '@/assets/withTimeLogo/loadingLogo.svg?react'; import Logo from '@/assets/withTimeLogo/logo_Blank.svg?react'; export default function DateCourseLoading() { + const { data } = useUserGrade(); return (
- Madeleine님만의 + {data?.result.username}님만의
데이트 코스 만드는 중...
diff --git a/src/components/dateCourse/dateCourseSearchFilterOption.tsx b/src/components/dateCourse/dateCourseSearchFilterOption.tsx index b9a84d3..b74b5c8 100644 --- a/src/components/dateCourse/dateCourseSearchFilterOption.tsx +++ b/src/components/dateCourse/dateCourseSearchFilterOption.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useRef, useState } from 'react'; +import React, { useEffect, useMemo, useRef, useState } from 'react'; import type { TDateCourseSearchFilterOption, TRegion } from '@/types/dateCourse/dateCourse'; import DATE_KEYWORD from '@/constants/dateKeywords'; @@ -38,7 +38,7 @@ export default function DateCourseSearchFilterOption({ if (type === 'time' && autoInit && (value == null || value === '')) { onChange(`${date} ${time}`); } - }, []); + }, [type, autoInit, value]); const handleDateClick = () => { dateInputRef.current?.showPicker?.(); @@ -66,17 +66,14 @@ export default function DateCourseSearchFilterOption({ refetch(); }; - let items = options?.map((label, idx) => ({ - label, - value: apiRequestValue && apiRequestValue[idx], - })); - - useEffect(() => { - items = options?.map((label, idx) => ({ - label, - value: apiRequestValue && apiRequestValue[idx], - })); - }, [options]); + const items = useMemo( + () => + options?.map((label, idx) => ({ + label, + value: apiRequestValue && apiRequestValue[idx], + })), + [options, apiRequestValue], + ); return (
diff --git a/src/components/dateCourse/info.tsx b/src/components/dateCourse/info.tsx index 87b2556..f617b9b 100644 --- a/src/components/dateCourse/info.tsx +++ b/src/components/dateCourse/info.tsx @@ -9,24 +9,17 @@ import Cash from '@/assets/icons/cash_Blank.svg?react'; import Location from '@/assets/icons/Location_Blank.svg?react'; import Spoon from '@/assets/icons/spoon_Blank.svg?react'; -export default function Info({ cashTag, locationTag, timeTag, MealTag, keywordTags }: TInfo) { - type TBudgetKey = keyof typeof Budget; - type TTotalTimeKey = keyof typeof TotalTime; - type TMealKey = keyof typeof Meal; - function isBudgetKey(v: string): v is TBudgetKey { - return Object.prototype.hasOwnProperty.call(Budget, v); - } - function isTotalTimeKey(v: string): v is TTotalTimeKey { - return Object.prototype.hasOwnProperty.call(TotalTime, v); - } - - function isMealKey(v: string): v is TMealKey { - return Object.prototype.hasOwnProperty.call(Meal, v); - } +type TBudgetKey = keyof typeof Budget; +type TTotalTimeKey = keyof typeof TotalTime; +type TMealKey = keyof typeof Meal; +const isBudgetKey = (v: string): v is TBudgetKey => Object.prototype.hasOwnProperty.call(Budget, v); +const isTotalTimeKey = (v: string): v is TTotalTimeKey => Object.prototype.hasOwnProperty.call(TotalTime, v); +const isMealKey = (v: string): v is TMealKey => Object.prototype.hasOwnProperty.call(Meal, v); +export default function Info({ cashTag, locationTag, timeTag, MealTag, keywordTags }: TInfo) { const label = isBudgetKey(cashTag) ? Budget[cashTag] : '알 수 없음'; const totalTime = isTotalTimeKey(timeTag) ? TotalTime[timeTag] : '알 수 없음'; - const meals = Array.isArray(MealTag) ? MealTag.filter(isMealKey).map((tag) => Meal[tag]) : []; + const meals = MealTag.filter(isMealKey).map((tag) => Meal[tag]); return (
diff --git a/src/components/dateCourse/infoElement.tsx b/src/components/dateCourse/infoElement.tsx index 793056f..4daf131 100644 --- a/src/components/dateCourse/infoElement.tsx +++ b/src/components/dateCourse/infoElement.tsx @@ -5,7 +5,7 @@ import KeywordButton from './keywordButton'; type TInfoElement = { children: ReactElement; title: string; - tags: string[] | string | undefined; + tags?: string[] | string; }; export default function InfoElement({ children, title, tags }: TInfoElement) { return ( diff --git a/src/components/dateCourse/timeline.tsx b/src/components/dateCourse/timeline.tsx index eb987b9..29d989e 100644 --- a/src/components/dateCourse/timeline.tsx +++ b/src/components/dateCourse/timeline.tsx @@ -14,7 +14,11 @@ function Timeline({ end = false, image, name, placeCategoryResponseList, roadNam const [open, setOpen] = useState(false); return (
-
(end ? undefined : setOpen(!open))}> +
(end ? undefined : setOpen(!open))} + >
{time.split(':')[0]}:{time.split(':')[1]}
@@ -29,7 +33,7 @@ function Timeline({ end = false, image, name, placeCategoryResponseList, roadNam
{open && ( -
+
{signatureDish && (
@@ -37,7 +41,7 @@ function Timeline({ end = false, image, name, placeCategoryResponseList, roadNam
WithTime Pick
- +
)} {image && } @@ -49,12 +53,12 @@ function Timeline({ end = false, image, name, placeCategoryResponseList, roadNam
- {averagePrice}원 + {averagePrice != null ? `${averagePrice}원` : '가격 정보 없음'}
- {placeCategoryResponseList!.map((tag, idx) => { + {(placeCategoryResponseList ?? []).map((tag, idx) => { return ; })}
diff --git a/src/components/home/level.tsx b/src/components/home/level.tsx index d057f19..b908cf9 100644 --- a/src/components/home/level.tsx +++ b/src/components/home/level.tsx @@ -12,7 +12,7 @@ function Level({ grade, nextRequiredPoint }: IGradeInfo) { useEffect(() => { setPercentage(getProgressToNextGrade(grade, nextRequiredPoint)); - }, [nextRequiredPoint]); + }, [nextRequiredPoint, grade]); return ( diff --git a/src/components/modal/dateCourseSearchFilterModal.tsx b/src/components/modal/dateCourseSearchFilterModal.tsx index 879ff3a..4ccd896 100644 --- a/src/components/modal/dateCourseSearchFilterModal.tsx +++ b/src/components/modal/dateCourseSearchFilterModal.tsx @@ -1,5 +1,5 @@ // DateCourseSearchFilterModal.tsx -import { useEffect, useMemo, useState } from 'react'; +import { useMemo } from 'react'; import { useLocation } from 'react-router-dom'; import { DateCourseQuestion } from '@/constants/dateCourseQuestion'; @@ -13,6 +13,7 @@ import { TotalTimeMealValidation, } from '@/utils/dateCourseValidation'; +import useGetBookmarkedCourse from '@/hooks/course/useGetBookmarkedCourse'; import useGetCourse from '@/hooks/course/useGetCourse'; import Button from '../common/Button'; @@ -65,19 +66,12 @@ function computeErrors(f: { budget: any; dateDurationTime: any; mealTypes?: any[ } export default function DateCourseSearchFilterModal({ onClose }: TProps) { - const { budget, datePlaces, dateDurationTime, startTime, mealTypes, transportation, userPreferredKeywords, setField } = useFilterStore(); - const [bookmarkedValue, setBookmarkedValue] = useState(false); - console.warn(bookmarkedValue); const location = useLocation(); - useEffect(() => { - if (location.pathname === '/bookmarkedCourse') { - setBookmarkedValue(true); - } else { - setBookmarkedValue(false); - } - }, [location]); - // API 데이터 (현재 필터 기준) - const { data } = useGetCourse({ + const isBookmarked = location.pathname === '/bookmarkedCourse'; + + const { budget, datePlaces, dateDurationTime, startTime, mealTypes, transportation, userPreferredKeywords, setField } = useFilterStore(); + + const commonParams = { budget, datePlaces, dateDurationTime, @@ -87,9 +81,14 @@ export default function DateCourseSearchFilterModal({ onClose }: TProps) { userPreferredKeywords, size: 5, page: 1, - }); + isBookmarked, + }; + + const { data: courseData } = useGetCourse(commonParams); + const { data: bookmarkedData } = useGetBookmarkedCourse(commonParams); + + const data = isBookmarked ? bookmarkedData : courseData; - // 질문 목록 (filterTitle 없는 항목 제외) const Questions = useMemo( () => (Array.isArray(DateCourseQuestion) ? DateCourseQuestion.slice(0, 7) : []) @@ -101,7 +100,6 @@ export default function DateCourseSearchFilterModal({ onClose }: TProps) { [], ); - // 인덱스 → 현재 값 매핑 const valueByIndex = (idx: number) => { switch (idx) { case 0: @@ -123,7 +121,6 @@ export default function DateCourseSearchFilterModal({ onClose }: TProps) { } }; - // ✅ 에러는 상태로 들고 있지 않고, 항상 파생 계산 const errorMessages = useMemo( () => computeErrors({ @@ -136,11 +133,8 @@ export default function DateCourseSearchFilterModal({ onClose }: TProps) { [budget, dateDurationTime, mealTypes, userPreferredKeywords, startTime], ); - // 값 갱신 (검증 호출 없음) const updateByIndex = (idx: number, raw: any) => { let v = raw; - - // 배열 필드는 타입 보정 if ([1, 3, 6].includes(idx) && !Array.isArray(v)) v = []; switch (idx) { diff --git a/src/constants/dateCourseQuestion.ts b/src/constants/dateCourseQuestion.ts index 7ed5686..a41537b 100644 --- a/src/constants/dateCourseQuestion.ts +++ b/src/constants/dateCourseQuestion.ts @@ -47,7 +47,7 @@ export const DateCourseQuestion = [ options: ['도보', '자차', '대중교통'], apiRequestValue: ['WALK', 'CAR', 'PUBLICTRAN'], type: 'choice', - filterTitle: '', + filterTitle: '이동 수단', }, { id: 5, diff --git a/src/hooks/course/useGetBookmarkedCourse.ts b/src/hooks/course/useGetBookmarkedCourse.ts index 8908f4b..07bc418 100644 --- a/src/hooks/course/useGetBookmarkedCourse.ts +++ b/src/hooks/course/useGetBookmarkedCourse.ts @@ -8,6 +8,7 @@ import { dateCourseKeys } from '@/queryKey/queryKey'; type TUseGetBookmarkedCourseProps = TCourseFilter & { size: number; page: number; + isBookmarked: boolean; }; export default function useGetBookmarkedCourse({ budget, @@ -19,6 +20,7 @@ export default function useGetBookmarkedCourse({ startTime, size, page, + isBookmarked, }: TUseGetBookmarkedCourseProps) { return useCoreQuery( dateCourseKeys.getBookmarkedDateCourse({ @@ -44,5 +46,8 @@ export default function useGetBookmarkedCourse({ size, page, }), + { + enabled: isBookmarked, + }, ); } diff --git a/src/hooks/course/useGetCourse.ts b/src/hooks/course/useGetCourse.ts index 5d5522c..03b871b 100644 --- a/src/hooks/course/useGetCourse.ts +++ b/src/hooks/course/useGetCourse.ts @@ -8,6 +8,7 @@ import { dateCourseKeys } from '@/queryKey/queryKey'; type TUseGetCourseProps = TCourseFilter & { size: number; page: number; + isBookmarked: boolean; }; export default function useGetCourse({ budget, @@ -19,10 +20,14 @@ export default function useGetCourse({ startTime, size, page, + isBookmarked, }: TUseGetCourseProps) { return useCoreQuery( dateCourseKeys.getDateCourse({ budget, datePlaces, mealTypes, dateDurationTime, transportation, userPreferredKeywords, startTime, size, page }) .queryKey, () => getDateCourse({ budget, datePlaces, mealTypes, dateDurationTime, transportation, userPreferredKeywords, startTime, size, page }), + { + enabled: !isBookmarked, + }, ); } diff --git a/src/layout/layout.tsx b/src/layout/layout.tsx index 6ff1399..e7d17f5 100644 --- a/src/layout/layout.tsx +++ b/src/layout/layout.tsx @@ -1,5 +1,7 @@ import { Outlet } from 'react-router-dom'; +import { ClearOnLeave } from '@/utils/clearStorageOnLeave'; + import Footer from '@/components/layout/Footer'; import Header from '@/components/layout/Header'; @@ -11,6 +13,7 @@ function Layout() {
+
); diff --git a/src/pages/dateCourse/BookmarkedDateCourse.tsx b/src/pages/dateCourse/BookmarkedDateCourse.tsx index 72b1352..835f1bd 100644 --- a/src/pages/dateCourse/BookmarkedDateCourse.tsx +++ b/src/pages/dateCourse/BookmarkedDateCourse.tsx @@ -1,4 +1,4 @@ -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import useGetBookmarkedCourse from '@/hooks/course/useGetBookmarkedCourse'; @@ -28,6 +28,11 @@ function BookmarkedDateCourse() { startTime, }); + (useEffect(() => { + setCurrent(1); + }), + [budget, datePlaces, dateDurationTime, startTime, mealTypes, transportation, userPreferredKeywords]); + return (
@@ -43,7 +48,7 @@ function BookmarkedDateCourse() {
- {data?.result.dateCourseList.map((course) => { + {data?.result?.dateCourseList?.map((course) => { return ; })}
diff --git a/src/pages/dateCourse/CoursePage.tsx b/src/pages/dateCourse/CoursePage.tsx index 0cbc032..785b3f6 100644 --- a/src/pages/dateCourse/CoursePage.tsx +++ b/src/pages/dateCourse/CoursePage.tsx @@ -51,7 +51,7 @@ export default function Course() {
- {gradeData?.result.username} 님만의 데이트 코스 + {gradeData?.result.username ?? '회원님의'} 님만의 데이트 코스
- {data?.result.dateCourseList.map((course) => { - return ; + {data?.result.dateCourseList.map((course, idx) => { + return ; })}
- +
diff --git a/src/pages/dateCourse/FindDateCourse.tsx b/src/pages/dateCourse/FindDateCourse.tsx index 75594fc..f952293 100644 --- a/src/pages/dateCourse/FindDateCourse.tsx +++ b/src/pages/dateCourse/FindDateCourse.tsx @@ -1,4 +1,4 @@ -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import useGetCourse from '@/hooks/course/useGetCourse'; @@ -17,6 +17,10 @@ function FindDateCourse() { const [current, setCurrent] = useState(1); const navigate = useNavigate(); const { budget, datePlaces, dateDurationTime, startTime, mealTypes, transportation, userPreferredKeywords } = useFilterStore(); + useEffect(() => { + setCurrent(1); + }, [budget, datePlaces, dateDurationTime, startTime, mealTypes, transportation, userPreferredKeywords]); + const { data: courseData } = useGetCourse({ page: current, size: 5, diff --git a/src/pages/dateCourse/MakeCourseResult.tsx b/src/pages/dateCourse/MakeCourseResult.tsx index a7ad937..6618e44 100644 --- a/src/pages/dateCourse/MakeCourseResult.tsx +++ b/src/pages/dateCourse/MakeCourseResult.tsx @@ -11,13 +11,13 @@ import DateCourseLoading from '@/components/dateCourse/dateCourseLoading'; import Button from '../../components/common/Button'; import Reload from '@/assets/icons/arrow_spin.svg?react'; -import Logo from '@/assets/withTimeLogo//logo_Blank.svg?react'; +import Logo from '@/assets/withTimeLogo/logo_Blank.svg?react'; import useDateCourseResultStore from '@/store/useDateCourseResultStore'; import useFilterStore from '@/store/useFilterStore'; export default function MakeCourseResult() { const navigate = useNavigate(); - const { setAll, ...courseData } = useDateCourseResultStore(); + const { setAll, resetDateCourseResultStore, ...courseData } = useDateCourseResultStore(); const { useMakeCourse } = useCourse(); const { budget, datePlaces, dateDurationTime, mealTypes, transportation, userPreferredKeywords, startTime } = useFilterStore(); const { mutate: makeCourseMutate, isPending } = useMakeCourse; @@ -33,7 +33,7 @@ export default function MakeCourseResult() { transportation: transportation!, userPreferredKeywords, startTime: startTime!, - excludedCourseSignatures: JSON.parse(localStorage.getItem('signature') ?? '[]'), + excludedCourseSignatures: SigStorage.get(), }, { onSuccess: (data) => { diff --git a/src/pages/dateCourse/MakeCourseStep.tsx b/src/pages/dateCourse/MakeCourseStep.tsx index 8077a38..e3ce16a 100644 --- a/src/pages/dateCourse/MakeCourseStep.tsx +++ b/src/pages/dateCourse/MakeCourseStep.tsx @@ -5,6 +5,7 @@ import { useNavigate, useParams } from 'react-router-dom'; import type { IQuestion } from '@/types/dateCourse/dateCourse'; import { DateCourseQuestion } from '@/constants/dateCourseQuestion'; +import { SigStorage } from '@/utils/appendSignature'; import { BudgetTimeValidation, DateTimeStartValidation, @@ -60,51 +61,40 @@ export default function MakeCourseStep() { else navigate('/makeCourse'); }; + const stepFieldMap = { + 1: 'budget', + 2: 'datePlaces', + 3: 'dateDurationTime', + 4: 'mealTypes', + 5: 'transportation', + 6: 'userPreferredKeywords', + 7: 'startTime', + } as const; + + const fieldValues = { + budget, + datePlaces, + dateDurationTime, + mealTypes, + transportation, + userPreferredKeywords, + startTime, + }; + const valueByStep = (idx: number): string | string[] | null => { - switch (idx) { - case 1: - return budget; - case 2: - return datePlaces; - case 3: - return dateDurationTime; - case 4: - return mealTypes; - case 5: - return transportation; - case 6: - return userPreferredKeywords; - case 7: - return startTime; - default: - return null; - } + const fieldName = stepFieldMap[idx as keyof typeof stepFieldMap]; + return fieldName ? fieldValues[fieldName] : null; }; const updateByStep = (idx: number, v: any) => { - switch (idx) { - case 1: - setField('budget', v ?? null); - break; - case 2: - setField('datePlaces', Array.isArray(v) ? v : []); - break; - case 3: - setField('dateDurationTime', v ?? null); - break; - case 4: - setField('mealTypes', Array.isArray(v) ? v : []); - break; - case 5: - setField('transportation', v ?? null); - break; - case 6: - setField('userPreferredKeywords', Array.isArray(v) ? v : []); - break; - case 7: - setField('startTime', v ?? null); - break; + const fieldName = stepFieldMap[idx as keyof typeof stepFieldMap]; + if (!fieldName) return; + + // 배열 필드 처리 + if ([2, 4, 6].includes(idx) && !Array.isArray(v)) { + v = []; } + setField(fieldName, v ?? null); }; const currentAnswer = valueByStep(currentStep); @@ -138,7 +128,7 @@ export default function MakeCourseStep() { transportation: transportation!, userPreferredKeywords, startTime: startTime!, - excludedCourseSignatures: [], + excludedCourseSignatures: SigStorage.get(), }, { onSuccess: (data) => { diff --git a/src/store/useDateCourseResultStore.ts b/src/store/useDateCourseResultStore.ts index 445fbac..981d8e4 100644 --- a/src/store/useDateCourseResultStore.ts +++ b/src/store/useDateCourseResultStore.ts @@ -26,7 +26,7 @@ const INITIAL_DATA: TDataState = { const useDateCourseResultStore = create((set) => ({ ...INITIAL_DATA, - resetDateCourseResultStore: () => set(INITIAL_DATA), + resetDateCourseResultStore: () => set({ ...INITIAL_DATA }), setAll: (payload) => set((prev) => ({ ...prev, ...payload })), })); diff --git a/src/types/dateCourse/dateCourse.ts b/src/types/dateCourse/dateCourse.ts index 85a51ce..812dffe 100644 --- a/src/types/dateCourse/dateCourse.ts +++ b/src/types/dateCourse/dateCourse.ts @@ -15,7 +15,7 @@ export type TTag = { code: string; }; -type TSignatureDish = { +export type TSignatureDish = { ItemId: number; imageUrl: string; name: string; @@ -125,7 +125,7 @@ export type TDatePlaces = { placeCategoryResponseList: TPlaceCategoryResponseList[]; }; -type TPlaceCategoryResponseList = { +export type TPlaceCategoryResponseList = { placeCategoryType: string; description: string; code: string; @@ -213,6 +213,7 @@ export type TGetBookmarkedDateCourseResponse = TCommonResponse<{ currentPage: number; currentSize: number; hasNextPage: boolean; + totalCount: number; }>; export type TCourseFilter = { diff --git a/src/utils/clearStorageOnLeave.tsx b/src/utils/clearStorageOnLeave.tsx new file mode 100644 index 0000000..95a39de --- /dev/null +++ b/src/utils/clearStorageOnLeave.tsx @@ -0,0 +1,19 @@ +import { useEffect, useRef } from 'react'; +import { useLocation } from 'react-router-dom'; + +export function ClearOnLeave({ from, keys }: { from: string | RegExp; keys: string[] }) { + const location = useLocation(); + const prev = useRef(location.pathname); + + useEffect(() => { + const wasIn = typeof from === 'string' ? prev.current.startsWith(from) : (from as RegExp).test(prev.current); + const nowIn = typeof from === 'string' ? location.pathname.startsWith(from) : (from as RegExp).test(location.pathname); + + if (wasIn && !nowIn) { + keys.forEach((k) => localStorage.removeItem(k)); + } + prev.current = location.pathname; + }, [location.pathname, from, keys]); + + return null; +} diff --git a/src/utils/dateCourseValidation.tsx b/src/utils/dateCourseValidation.tsx index 4e19da2..e718fc1 100644 --- a/src/utils/dateCourseValidation.tsx +++ b/src/utils/dateCourseValidation.tsx @@ -1,5 +1,6 @@ export const timeMap: Record = { ONETOTWO: 1.5, + TWOTOTHREE: 2.5, THREETOFOUR: 3.5, HALFDAY: 5.0, ALLDAY: 8.0, From 1c321ba4e7d3c200c43b99730a58683142f3e1db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=97=B0=EC=A7=84?= Date: Fri, 15 Aug 2025 21:58:00 +0900 Subject: [PATCH 12/17] =?UTF-8?q?feat:=20=EC=BD=94=EB=93=9C=EB=A6=AC?= =?UTF-8?q?=EB=B7=B0=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/dateCourse/dateCourseSearchFilterOption.tsx | 2 +- src/pages/setting/DeleteConfirmPage.tsx | 2 -- src/pages/setting/DeleteReasonPage.tsx.tsx | 3 --- 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/components/dateCourse/dateCourseSearchFilterOption.tsx b/src/components/dateCourse/dateCourseSearchFilterOption.tsx index b74b5c8..d8fd29f 100644 --- a/src/components/dateCourse/dateCourseSearchFilterOption.tsx +++ b/src/components/dateCourse/dateCourseSearchFilterOption.tsx @@ -36,7 +36,7 @@ export default function DateCourseSearchFilterOption({ useEffect(() => { if (type === 'time' && autoInit && (value == null || value === '')) { - onChange(`${date} ${time}`); + onChange(`${date}T${time}`); } }, [type, autoInit, value]); diff --git a/src/pages/setting/DeleteConfirmPage.tsx b/src/pages/setting/DeleteConfirmPage.tsx index 0297afa..87f1434 100644 --- a/src/pages/setting/DeleteConfirmPage.tsx +++ b/src/pages/setting/DeleteConfirmPage.tsx @@ -4,7 +4,6 @@ import { useNavigate } from 'react-router-dom'; import { useAccount } from '@/hooks/auth/useAccount'; import CommonAuthInput from '@/components/auth/commonAuthInput'; -import Header from '@/components/layout/Header'; import { queryClient } from '@/api/queryClient'; import ArrowLeftCircle from '@/assets/icons/Arrow_left_circle.svg?react'; @@ -71,7 +70,6 @@ export default function DeleteConfirmPage() { return ( <> -
{/* 뒤로가기 */} diff --git a/src/pages/setting/DeleteReasonPage.tsx.tsx b/src/pages/setting/DeleteReasonPage.tsx.tsx index 9141a28..ae491ca 100644 --- a/src/pages/setting/DeleteReasonPage.tsx.tsx +++ b/src/pages/setting/DeleteReasonPage.tsx.tsx @@ -3,7 +3,6 @@ import { useState } from 'react'; import { Link, useNavigate } from 'react-router-dom'; import ReasonButton from '@/components/common/ReansonButton'; -import Header from '@/components/layout/Header'; import ArrowLeftCircle from '@/assets/icons/Arrow_left_circle.svg?react'; @@ -23,8 +22,6 @@ export default function DeleteReasonPage() { return ( <> -
-
{/* 뒤로가기 */} From 70c431953117ec2736b91cade63787e6ceecd7e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=97=B0=EC=A7=84?= Date: Fri, 15 Aug 2025 21:59:19 +0900 Subject: [PATCH 13/17] =?UTF-8?q?fix:=20=EB=B9=8C=EB=93=9C=20=EC=97=90?= =?UTF-8?q?=EB=9F=AC=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/dateCourse/BookmarkedDateCourse.tsx | 1 + src/pages/dateCourse/CoursePage.tsx | 1 + src/pages/dateCourse/FindDateCourse.tsx | 1 + 3 files changed, 3 insertions(+) diff --git a/src/pages/dateCourse/BookmarkedDateCourse.tsx b/src/pages/dateCourse/BookmarkedDateCourse.tsx index 835f1bd..e70bd83 100644 --- a/src/pages/dateCourse/BookmarkedDateCourse.tsx +++ b/src/pages/dateCourse/BookmarkedDateCourse.tsx @@ -26,6 +26,7 @@ function BookmarkedDateCourse() { transportation, userPreferredKeywords, startTime, + isBookmarked: true, }); (useEffect(() => { diff --git a/src/pages/dateCourse/CoursePage.tsx b/src/pages/dateCourse/CoursePage.tsx index 785b3f6..eab7b5b 100644 --- a/src/pages/dateCourse/CoursePage.tsx +++ b/src/pages/dateCourse/CoursePage.tsx @@ -29,6 +29,7 @@ export default function Course() { transportation, userPreferredKeywords, startTime, + isBookmarked: true, }); const { data: gradeData } = useUserGrade(); return ( diff --git a/src/pages/dateCourse/FindDateCourse.tsx b/src/pages/dateCourse/FindDateCourse.tsx index f952293..6ae4177 100644 --- a/src/pages/dateCourse/FindDateCourse.tsx +++ b/src/pages/dateCourse/FindDateCourse.tsx @@ -31,6 +31,7 @@ function FindDateCourse() { transportation, userPreferredKeywords, startTime, + isBookmarked: false, }); return ( From 12a29ef59b347b1cd5b08eb356bc1e80125b0f58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=97=B0=EC=A7=84?= Date: Fri, 15 Aug 2025 22:00:52 +0900 Subject: [PATCH 14/17] =?UTF-8?q?fix:=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/dateCourse/dateCourse.tsx | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/components/dateCourse/dateCourse.tsx b/src/components/dateCourse/dateCourse.tsx index bd782c9..8d3bd48 100644 --- a/src/components/dateCourse/dateCourse.tsx +++ b/src/components/dateCourse/dateCourse.tsx @@ -61,9 +61,20 @@ function DateCourse({ defaultOpen = false, name, make, dateCourseId, isBookmarke console.error('dateCourseId가 없어 북마크를 생성할 수 없습니다'); return; } - postBookmark({ - dateCourseId: dateCourseID!, - }); + postBookmark( + { + dateCourseId: dateCourseID!, + }, + { + onSuccess: (response) => { + setDateCourseID(response.result.dateCourseId); + setBookmarked(true); + }, + onError: () => { + console.error('북마크 도중 에러가 발생하였습니다.'); + }, + }, + ); } }; From 1ff53533b4a2eb217c29e63cdd0f2f301432e9bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=97=B0=EC=A7=84?= Date: Fri, 15 Aug 2025 22:02:42 +0900 Subject: [PATCH 15/17] =?UTF-8?q?fix:=20lint=20=EC=97=90=EB=9F=AC=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/clearStorageOnLeave.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/utils/clearStorageOnLeave.tsx b/src/utils/clearStorageOnLeave.tsx index 95a39de..3682c54 100644 --- a/src/utils/clearStorageOnLeave.tsx +++ b/src/utils/clearStorageOnLeave.tsx @@ -1,16 +1,19 @@ import { useEffect, useRef } from 'react'; import { useLocation } from 'react-router-dom'; +import useDateCourseResultStore from '@/store/useDateCourseResultStore'; + export function ClearOnLeave({ from, keys }: { from: string | RegExp; keys: string[] }) { const location = useLocation(); const prev = useRef(location.pathname); - + const { resetDateCourseResultStore } = useDateCourseResultStore(); useEffect(() => { const wasIn = typeof from === 'string' ? prev.current.startsWith(from) : (from as RegExp).test(prev.current); const nowIn = typeof from === 'string' ? location.pathname.startsWith(from) : (from as RegExp).test(location.pathname); if (wasIn && !nowIn) { keys.forEach((k) => localStorage.removeItem(k)); + resetDateCourseResultStore(); } prev.current = location.pathname; }, [location.pathname, from, keys]); From 07a715527c1f5b2bae0c6d37a3e2cae35a8c88ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=97=B0=EC=A7=84?= Date: Fri, 15 Aug 2025 22:04:37 +0900 Subject: [PATCH 16/17] =?UTF-8?q?fix:=20lint=20=EC=97=90=EB=9F=AC=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/dateCourse/MakeCourseResult.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/dateCourse/MakeCourseResult.tsx b/src/pages/dateCourse/MakeCourseResult.tsx index 6618e44..49b72f4 100644 --- a/src/pages/dateCourse/MakeCourseResult.tsx +++ b/src/pages/dateCourse/MakeCourseResult.tsx @@ -17,7 +17,7 @@ import useFilterStore from '@/store/useFilterStore'; export default function MakeCourseResult() { const navigate = useNavigate(); - const { setAll, resetDateCourseResultStore, ...courseData } = useDateCourseResultStore(); + const { setAll, ...courseData } = useDateCourseResultStore(); const { useMakeCourse } = useCourse(); const { budget, datePlaces, dateDurationTime, mealTypes, transportation, userPreferredKeywords, startTime } = useFilterStore(); const { mutate: makeCourseMutate, isPending } = useMakeCourse; From 4547418a5ae1604b9dde8d463e20480daed8d189 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=97=B0=EC=A7=84?= Date: Fri, 15 Aug 2025 22:06:55 +0900 Subject: [PATCH 17/17] =?UTF-8?q?feat:=20=EC=9C=A0=ED=9A=A8=EC=84=B1=20?= =?UTF-8?q?=EA=B2=80=EC=82=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/auth/LoginPage.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/pages/auth/LoginPage.tsx b/src/pages/auth/LoginPage.tsx index d1efcce..176aef5 100644 --- a/src/pages/auth/LoginPage.tsx +++ b/src/pages/auth/LoginPage.tsx @@ -1,4 +1,4 @@ -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import type { SubmitHandler } from 'react-hook-form'; import { useForm, useWatch } from 'react-hook-form'; import { useNavigate } from 'react-router-dom'; @@ -68,6 +68,10 @@ export default function Login() { window.location.href = `${baseUrl}`; }; + useEffect(() => { + setError(''); + }, [watchedEmail, watchedPassword]); + return (