diff --git a/eslint.config.mjs b/eslint.config.mjs index 373d4d4..3787778 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -10,7 +10,7 @@ import tsConfig from './eslint/typescript.mjs'; export default [ { - ignores: ['src/vite-env.d.ts'], + ignores: ['src/vite-env.d.ts', 'public/firebase-messaging-sw.js'], }, { files: ['**/*.{js,mjs,cjs,ts,jsx,tsx}'], diff --git a/package.json b/package.json index 1a84e71..2c046f5 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "chart.js": "^4.5.0", "chartjs-plugin-datalabels": "^2.2.0", "clsx": "^2.1.1", + "firebase": "^12.0.0", "lodash": "^4.17.21", "lodash.throttle": "^4.1.1", "path": "^0.12.7", @@ -30,7 +31,9 @@ "react-chartjs-2": "^5.3.0", "react-dom": "^19.1.0", "react-hook-form": "^7.60.0", + "react-intersection-observer": "^9.16.0", "react-router-dom": "^7.6.0", + "react-spinners": "^0.17.0", "sonner": "^2.0.3", "tailwindcss": "^4.1.7", "wordcloud": "^1.2.3", diff --git a/public/firebase-messaging-sw.js b/public/firebase-messaging-sw.js new file mode 100644 index 0000000..ff4fef2 --- /dev/null +++ b/public/firebase-messaging-sw.js @@ -0,0 +1,42 @@ +/// +/* eslint-env serviceworker */ +/* global firebase importScripts clients */ +importScripts('https://www.gstatic.com/firebasejs/10.13.2/firebase-app-compat.js'); +importScripts('https://www.gstatic.com/firebasejs/10.13.2/firebase-messaging-compat.js'); + +firebase.initializeApp({ + apiKey: 'AIzaSyAjZqK2lhCOeX_P2Sf-_2IGEFlORchcO5w', + authDomain: 'withtime-ff471.firebaseapp.com', + projectId: 'withtime-ff471', + storageBucket: 'withtime-ff471.firebasestorage.app', + messagingSenderId: '47995224236', + appId: '1:47995224236:web:85371605ce4a6659529f09', + measurementId: 'G-5E8Q23LL4H', +}); + +const messaging = firebase.messaging(); + +self.addEventListener('push', function (event) { + try { + const payload = event.data.json(); + const title = payload.notification.title; + + const options = { + body: payload.notification.body, + icon: payload.notification.icon, + data: payload.notification.click_action, + }; + + event.waitUntil(self.registration.showNotification(title, options)); + } catch (error) { + console.error('Push event error:', error); + } +}); + +self.addEventListener('notificationclick', function (event) { + console.log(event.notification); + + event.notification.close(); + + event.waitUntil(clients.openWindow(event.notification.data).catch((error) => console.error('Failed to open window:', error))); +}); diff --git a/src/api/alarm/alarm.ts b/src/api/alarm/alarm.ts new file mode 100644 index 0000000..f1b9750 --- /dev/null +++ b/src/api/alarm/alarm.ts @@ -0,0 +1,18 @@ +import type { TRequestGetAlarm, TRequestPostDeviceToken, TResponseGetAlarm, TResponsePostDeviceToken } from '@/types/alarm/alarm'; + +import { axiosInstance } from '../axiosInstance'; + +export const getAlarm = async ({ size = 5, cursor }: TRequestGetAlarm): Promise => { + const { data } = await axiosInstance.get('/api/v1/alarms', { + params: { + size, + cursor, + }, + }); + return data; +}; + +export const postDeviceToken = async ({ deviceToken }: TRequestPostDeviceToken): Promise => { + const { data } = await axiosInstance.post('/api/v1/alarms/device-tokens', { deviceToken }); + return data; +}; diff --git a/src/components/alarmModal/alarm.tsx b/src/components/alarmModal/alarm.tsx new file mode 100644 index 0000000..c6f0a9e --- /dev/null +++ b/src/components/alarmModal/alarm.tsx @@ -0,0 +1,14 @@ +import type { TAlarm } from '@/types/alarm/alarm'; + +import ChevronForward from '@/assets/icons/default_arrows/chevron_forward.svg?react'; + +function Alarm({ title }: TAlarm) { + return ( + + {title} + + + ); +} + +export default Alarm; diff --git a/src/components/common/graySvgButton.tsx b/src/components/common/graySvgButton.tsx index 9c9d2d7..d074938 100644 --- a/src/components/common/graySvgButton.tsx +++ b/src/components/common/graySvgButton.tsx @@ -1,10 +1,10 @@ -import type { ReactElement } from 'react'; +import React from 'react'; import ArrowLeftCircle from '@/assets/icons/Arrow_left_circle.svg?react'; import ErrorCircle from '@/assets/icons/Error-circle_Fill.svg?react'; type TGraySVGButton = { - child?: ReactElement; + child?: React.ReactNode; type?: 'cancle' | 'backward'; onClick: () => void; size?: 'big' | 'default'; diff --git a/src/components/common/modalProvider.tsx b/src/components/common/modalProvider.tsx index 579d80a..8b626a8 100644 --- a/src/components/common/modalProvider.tsx +++ b/src/components/common/modalProvider.tsx @@ -1,9 +1,10 @@ import { useEffect } from 'react'; import { useLocation } from 'react-router-dom'; -import DateCourseSearchFilterModal from '../modal/dateCourseSearchFilterModal'; -import ErrorModal from '../modal/errorModal'; -import SettingsModal from '../modal/SettingModal'; +import AlarmModal from '@/components/modal/alarmModal'; +import DateCourseSearchFilterModal from '@/components/modal/dateCourseSearchFilterModal'; +import ErrorModal from '@/components/modal/errorModal'; +import SettingsModal from '@/components/modal/SettingModal'; import useModalStore from '@/store/useModalStore'; @@ -13,12 +14,14 @@ export const MODAL_TYPES = { ErrorModal: 'ErrorModal', DateCourseSearchFilterModal: 'DateCourseSearchFilterModal', SettingsModal: 'SettingsModal', //설정 모달 추가 + AlarmModal: 'AlarmModal', }; export const MODAL_COMPONENTS = { [MODAL_TYPES.ErrorModal]: ErrorModal, [MODAL_TYPES.DateCourseSearchFilterModal]: DateCourseSearchFilterModal, [MODAL_TYPES.SettingsModal]: SettingsModal, + [MODAL_TYPES.AlarmModal]: AlarmModal, }; export default function ModalProvider() { diff --git a/src/components/layout/Header.tsx b/src/components/layout/Header.tsx index ccb6d17..20011d7 100644 --- a/src/components/layout/Header.tsx +++ b/src/components/layout/Header.tsx @@ -2,21 +2,22 @@ import { useState } from 'react'; import { Link } from 'react-router-dom'; import MobileMenu from './MobileMenu'; -import SettingsModal from '../modal/SettingModal'; +import { MODAL_TYPES } from '../common/modalProvider'; import BurgerIcon from '@/assets/icons/Burger_fill.svg?react'; import ClearIcon from '@/assets/icons/Clear.svg?react'; import NotificationsIcon from '@/assets/icons/notifications_Blank.svg?react'; import SettingsIcon from '@/assets/icons/settings_Blank.svg?react'; import NavbarLogo from '@/assets/withTimeLogo/navbarLogo.svg?react'; +import useModalStore from '@/store/useModalStore'; interface IHeaderProps { mode?: 'full' | 'minimal'; // full: nav + border | minimal: 로고만 } export default function Header({ mode = 'full' }: IHeaderProps) { - const [isSettingsOpen, setIsSettingsOpen] = useState(false); //설정 모달 const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false); // 모바일 메뉴 + const { openModal } = useModalStore(); const showNav = mode === 'full'; const showBorder = mode === 'full'; @@ -56,10 +57,10 @@ export default function Header({ mode = 'full' }: IHeaderProps) { {/* 아이콘 버튼 */} - + openModal(MODAL_TYPES.AlarmModal)}> - - setIsSettingsOpen(true)}> + + openModal(MODAL_TYPES.SettingsModal)}> @@ -83,10 +84,7 @@ export default function Header({ mode = 'full' }: IHeaderProps) { {/* 모바일 메뉴 */} - {isMobileMenuOpen && setIsMobileMenuOpen(false)} onOpenSettings={() => setIsSettingsOpen(true)} />} - - {/* 설정 모달 */} - {isSettingsOpen && setIsSettingsOpen(false)} />} + {isMobileMenuOpen && setIsMobileMenuOpen(false)} onOpenSettings={() => openModal(MODAL_TYPES.SettingsModal)} />} ); } diff --git a/src/components/layout/MobileMenu.tsx b/src/components/layout/MobileMenu.tsx index c0373ca..d8cee30 100644 --- a/src/components/layout/MobileMenu.tsx +++ b/src/components/layout/MobileMenu.tsx @@ -1,8 +1,11 @@ import { Link } from 'react-router-dom'; +import { MODAL_TYPES } from '../common/modalProvider'; + import ClearIcon from '@/assets/icons/Clear.svg?react'; import NotificationsIcon from '@/assets/icons/notifications_Blank.svg?react'; import SettingsIcon from '@/assets/icons/settings_Blank.svg?react'; +import useModalStore from '@/store/useModalStore'; interface IMobileMenuProps { onClose: () => void; @@ -10,6 +13,7 @@ interface IMobileMenuProps { } export default function MobileMenu({ onClose, onOpenSettings }: IMobileMenuProps) { + const { openModal } = useModalStore(); return ( <> {/* 배경 오버레이 */} @@ -46,9 +50,14 @@ export default function MobileMenu({ onClose, onOpenSettings }: IMobileMenuProps {/* 알림, 설정 */} - + { + openModal(MODAL_TYPES.AlarmModal); + onClose(); + }} + > - + { diff --git a/src/components/modal/alarmModal.tsx b/src/components/modal/alarmModal.tsx new file mode 100644 index 0000000..ab1e071 --- /dev/null +++ b/src/components/modal/alarmModal.tsx @@ -0,0 +1,49 @@ +import { useEffect } from 'react'; +import { useInView } from 'react-intersection-observer'; +import ClipLoader from 'react-spinners/ClipLoader'; + +import { useGetAlarm } from '@/hooks/alarm/useGetAlarm'; + +import Alarm from '../alarmModal/alarm'; +import Modal from '../common/modal'; + +import ErrorComponent from '@/pages/common/Error'; + +type TAlarmModalProps = { + onClose: () => void; +}; + +function AlarmModal({ onClose }: TAlarmModalProps) { + const { data, fetchNextPage, isFetching, hasNextPage, error } = useGetAlarm({ size: 5 }); + const { ref, inView } = useInView({ + threshold: 0, + }); + + useEffect(() => { + if (inView) { + if (!isFetching && hasNextPage) { + fetchNextPage(); + } + } + }, [inView, isFetching, hasNextPage, fetchNextPage]); + + if (error) { + return ; + } + + return ( + + + {(!data?.pages?.length || data.pages.every((page) => page.result.alarmList.length === 0)) && ( + 아직 알림이 없습니다 + )} + {data?.pages.map((alarmList) => alarmList.result.alarmList.map((alarm) => ))} + + {isFetching && hasNextPage && } + + + + ); +} + +export default AlarmModal; diff --git a/src/firebase/firebase.ts b/src/firebase/firebase.ts new file mode 100644 index 0000000..2762064 --- /dev/null +++ b/src/firebase/firebase.ts @@ -0,0 +1,41 @@ +// src/firebase/firebase.ts +import { initializeApp } from 'firebase/app'; +import { getMessaging, getToken } from 'firebase/messaging'; + +const firebaseConfig = { + apiKey: import.meta.env.VITE_FIREBASE_API_KEY, + authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN, + projectId: import.meta.env.VITE_PROJECT_ID, + storageBucket: import.meta.env.VITE_STORAGE_BUCKET, + messagingSenderId: import.meta.env.VITE_MESSAGE_SENDER_ID, + appId: import.meta.env.VITE_APP_ID, + measurementId: import.meta.env.VITE_MEASUREMENT_ID, +}; + +const app = initializeApp(firebaseConfig); +const messaging = getMessaging(app); + +export const generateToken = async () => { + try { + const token = await getToken(messaging, { + vapidKey: import.meta.env.VITE_FIREBASE_VAPID_KEY, + }); + if (!token) { + console.warn('FCM 토큰 생성에 실패했습니다. 알림 권한을 확인해주세요.'); + } + return token; + } catch (error) { + console.error('FCM 토큰 생성 중 오류 발생:', error); + return null; + } +}; + +export const registerServiceWorker = async () => { + try { + if ('serviceWorker' in navigator) { + await navigator.serviceWorker.register('/firebase-messaging-sw.js'); + } + } catch (err) { + console.error('Service Worker registration failed:', err); + } +}; diff --git a/src/hooks/alarm/useDeviceToken.ts b/src/hooks/alarm/useDeviceToken.ts new file mode 100644 index 0000000..73523c4 --- /dev/null +++ b/src/hooks/alarm/useDeviceToken.ts @@ -0,0 +1,39 @@ +// src/hooks/alarm/useDeviceToken.ts +import { useEffect } from 'react'; +import { isSupported } from 'firebase/messaging'; + +import { postDeviceToken } from '@/api/alarm/alarm'; // 서버에 FCM 토큰 전송하는 API 함수 +import { generateToken, registerServiceWorker } from '@/firebase/firebase'; + +export const useDeviceToken = () => { + useEffect(() => { + const setupFCM = async () => { + if (!(await isSupported())) { + console.warn('FCM은 현재 브라우저에서 지원되지 않습니다.'); + return; + } + + await registerServiceWorker(); + const token = await generateToken(); + + if (token) { + try { + await postDeviceToken({ deviceToken: token }); // 서버에 전송 + } catch (err) { + console.error('디바이스 토큰 서버 전송 실패:', err); + } + } + }; + + const handleClick = () => { + setupFCM(); + window.removeEventListener('click', handleClick); + }; + + window.addEventListener('click', handleClick); + + return () => { + window.removeEventListener('click', handleClick); + }; + }, []); +}; diff --git a/src/hooks/alarm/useGetAlarm.ts b/src/hooks/alarm/useGetAlarm.ts new file mode 100644 index 0000000..1444051 --- /dev/null +++ b/src/hooks/alarm/useGetAlarm.ts @@ -0,0 +1,15 @@ +import { useInfiniteQuery } from '@tanstack/react-query'; + +import type { TRequestGetAlarm } from '@/types/alarm/alarm'; + +import { getAlarm } from '@/api/alarm/alarm'; +import { alarmKeys } from '@/queryKey/queryKey'; + +export const useGetAlarm = ({ cursor, size }: TRequestGetAlarm) => { + return useInfiniteQuery({ + queryKey: alarmKeys.getAlarm(size ?? 5, cursor).queryKey, + queryFn: ({ pageParam = cursor }) => getAlarm({ cursor: pageParam, size: size ?? 5 }), + initialPageParam: cursor, + getNextPageParam: (lastPage) => lastPage.result.cursor ?? undefined, + }); +}; diff --git a/src/pages/home/HomePage.tsx b/src/pages/home/HomePage.tsx index 964de68..619d3b3 100644 --- a/src/pages/home/HomePage.tsx +++ b/src/pages/home/HomePage.tsx @@ -1,3 +1,5 @@ +import { useDeviceToken } from '@/hooks/alarm/useDeviceToken'; + import Banner from '@/components/home/banner'; import DateCourseStore from '@/components/home/dateCourseStore'; import DateLocation from '@/components/home/dateLocation'; @@ -8,6 +10,8 @@ import Level from '@/components/home/level'; import WordCloudCard from '@/components/home/wordCloud'; function Home() { + useDeviceToken(); + return ( diff --git a/src/queryKey/queryKey.ts b/src/queryKey/queryKey.ts index 1e3fb30..c964258 100644 --- a/src/queryKey/queryKey.ts +++ b/src/queryKey/queryKey.ts @@ -3,3 +3,7 @@ import { createQueryKeys } from '@lukemorales/query-key-factory'; export const regionKeys = createQueryKeys('region', { search: (keyword: string) => [keyword], }); + +export const alarmKeys = createQueryKeys('alarm', { + getAlarm: (size: number, cursor?: number) => [size, cursor], +}); diff --git a/src/types/alarm/alarm.ts b/src/types/alarm/alarm.ts new file mode 100644 index 0000000..6f2b43d --- /dev/null +++ b/src/types/alarm/alarm.ts @@ -0,0 +1,22 @@ +import type { TCommonResponse } from '../common/common'; + +export type TRequestGetAlarm = { + size?: number; + cursor?: number; +}; +export type TResponseGetAlarm = TCommonResponse<{ + alarmList: TAlarm[]; + size: number; + hasNext: boolean; + cursor: number | null; +}>; +export type TRequestPostDeviceToken = { + deviceToken: string; +}; +export type TResponsePostDeviceToken = TCommonResponse<{}>; +export type TAlarm = { + id: number; + title: string; + alarmType: string; + isRead: boolean; +}; diff --git a/tsconfig.app.json b/tsconfig.app.json index 87da4c3..20f7021 100644 --- a/tsconfig.app.json +++ b/tsconfig.app.json @@ -26,5 +26,5 @@ "noFallthroughCasesInSwitch": true, "noUncheckedSideEffectImports": true }, - "include": ["src", "src/**/*", "**/*.ts", "**/*.tsx", "tailwind.config.ts"] + "include": ["src", "src/**/*", "**/*.ts", "**/*.tsx", "tailwind.config.ts", "public/firebase-messaging-sw.js"] } diff --git a/yarn.lock b/yarn.lock index af60bf3..95cbd8f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -377,6 +377,415 @@ "@eslint/core" "^0.15.1" levn "^0.4.1" +"@firebase/ai@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@firebase/ai/-/ai-2.0.0.tgz#c0324b48c2451b28d621c96517e056ab67576dc4" + integrity sha512-N/aSHjqOpU+KkYU3piMkbcuxzvqsOvxflLUXBAkYAPAz8wjE2Ye3BQDgKHEYuhMmEWqj6LFgEBUN8wwc6dfMTw== + dependencies: + "@firebase/app-check-interop-types" "0.3.3" + "@firebase/component" "0.7.0" + "@firebase/logger" "0.5.0" + "@firebase/util" "1.13.0" + tslib "^2.1.0" + +"@firebase/analytics-compat@0.2.24": + version "0.2.24" + resolved "https://registry.yarnpkg.com/@firebase/analytics-compat/-/analytics-compat-0.2.24.tgz#806c34ddd5c4869006eead08bfde575972d73ce2" + integrity sha512-jE+kJnPG86XSqGQGhXXYt1tpTbCTED8OQJ/PQ90SEw14CuxRxx/H+lFbWA1rlFtFSsTCptAJtgyRBwr/f00vsw== + dependencies: + "@firebase/analytics" "0.10.18" + "@firebase/analytics-types" "0.8.3" + "@firebase/component" "0.7.0" + "@firebase/util" "1.13.0" + tslib "^2.1.0" + +"@firebase/analytics-types@0.8.3": + version "0.8.3" + resolved "https://registry.yarnpkg.com/@firebase/analytics-types/-/analytics-types-0.8.3.tgz#d08cd39a6209693ca2039ba7a81570dfa6c1518f" + integrity sha512-VrIp/d8iq2g501qO46uGz3hjbDb8xzYMrbu8Tp0ovzIzrvJZ2fvmj649gTjge/b7cCCcjT0H37g1gVtlNhnkbg== + +"@firebase/analytics@0.10.18": + version "0.10.18" + resolved "https://registry.yarnpkg.com/@firebase/analytics/-/analytics-0.10.18.tgz#930d43504a02fe0128a8d82f8c5361911b0dbd04" + integrity sha512-iN7IgLvM06iFk8BeFoWqvVpRFW3Z70f+Qe2PfCJ7vPIgLPjHXDE774DhCT5Y2/ZU/ZbXPDPD60x/XPWEoZLNdg== + dependencies: + "@firebase/component" "0.7.0" + "@firebase/installations" "0.6.19" + "@firebase/logger" "0.5.0" + "@firebase/util" "1.13.0" + tslib "^2.1.0" + +"@firebase/app-check-compat@0.4.0": + version "0.4.0" + resolved "https://registry.yarnpkg.com/@firebase/app-check-compat/-/app-check-compat-0.4.0.tgz#94ac0cf9f66cab1d81a7b14e0c151dcc2684bc95" + integrity sha512-UfK2Q8RJNjYM/8MFORltZRG9lJj11k0nW84rrffiKvcJxLf1jf6IEjCIkCamykHE73C6BwqhVfhIBs69GXQV0g== + dependencies: + "@firebase/app-check" "0.11.0" + "@firebase/app-check-types" "0.5.3" + "@firebase/component" "0.7.0" + "@firebase/logger" "0.5.0" + "@firebase/util" "1.13.0" + tslib "^2.1.0" + +"@firebase/app-check-interop-types@0.3.3": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.3.tgz#ed9c4a4f48d1395ef378f007476db3940aa5351a" + integrity sha512-gAlxfPLT2j8bTI/qfe3ahl2I2YcBQ8cFIBdhAQA4I2f3TndcO+22YizyGYuttLHPQEpWkhmpFW60VCFEPg4g5A== + +"@firebase/app-check-types@0.5.3": + version "0.5.3" + resolved "https://registry.yarnpkg.com/@firebase/app-check-types/-/app-check-types-0.5.3.tgz#38ba954acf4bffe451581a32fffa20337f11d8e5" + integrity sha512-hyl5rKSj0QmwPdsAxrI5x1otDlByQ7bvNvVt8G/XPO2CSwE++rmSVf3VEhaeOR4J8ZFaF0Z0NDSmLejPweZ3ng== + +"@firebase/app-check@0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@firebase/app-check/-/app-check-0.11.0.tgz#a7e1d1e3f5ae36eabed1455db937114fe869ce8f" + integrity sha512-XAvALQayUMBJo58U/rxW02IhsesaxxfWVmVkauZvGEz3vOAjMEQnzFlyblqkc2iAaO82uJ2ZVyZv9XzPfxjJ6w== + dependencies: + "@firebase/component" "0.7.0" + "@firebase/logger" "0.5.0" + "@firebase/util" "1.13.0" + tslib "^2.1.0" + +"@firebase/app-compat@0.5.0": + version "0.5.0" + resolved "https://registry.yarnpkg.com/@firebase/app-compat/-/app-compat-0.5.0.tgz#7463e9fb8d84706787773d3660accedff4479d05" + integrity sha512-nUnNpOeRj0KZzVzHsyuyrmZKKHfykZ8mn40FtG28DeSTWeM5b/2P242Va4bmQpJsy5y32vfv50+jvdckrpzy7Q== + dependencies: + "@firebase/app" "0.14.0" + "@firebase/component" "0.7.0" + "@firebase/logger" "0.5.0" + "@firebase/util" "1.13.0" + tslib "^2.1.0" + +"@firebase/app-types@0.9.3": + version "0.9.3" + resolved "https://registry.yarnpkg.com/@firebase/app-types/-/app-types-0.9.3.tgz#8408219eae9b1fb74f86c24e7150a148460414ad" + integrity sha512-kRVpIl4vVGJ4baogMDINbyrIOtOxqhkZQg4jTq3l8Lw6WSk0xfpEYzezFu+Kl4ve4fbPl79dvwRtaFqAC/ucCw== + +"@firebase/app@0.14.0": + version "0.14.0" + resolved "https://registry.yarnpkg.com/@firebase/app/-/app-0.14.0.tgz#7132e96df95e85783922fd09750f08ab2ebfd699" + integrity sha512-APIAeKvRNFWKJLjIL8wLDjh7u8g6ZjaeVmItyqSjCdEkJj14UuVlus74D8ofsOMWh45HEwxwkd96GYbi+CImEg== + dependencies: + "@firebase/component" "0.7.0" + "@firebase/logger" "0.5.0" + "@firebase/util" "1.13.0" + idb "7.1.1" + tslib "^2.1.0" + +"@firebase/auth-compat@0.6.0": + version "0.6.0" + resolved "https://registry.yarnpkg.com/@firebase/auth-compat/-/auth-compat-0.6.0.tgz#1464ea6049b2ad0aae83b4fdcd5e5e5aba6b1c50" + integrity sha512-J0lGSxXlG/lYVi45wbpPhcWiWUMXevY4fvLZsN1GHh+po7TZVng+figdHBVhFheaiipU8HZyc7ljw1jNojM2nw== + dependencies: + "@firebase/auth" "1.11.0" + "@firebase/auth-types" "0.13.0" + "@firebase/component" "0.7.0" + "@firebase/util" "1.13.0" + tslib "^2.1.0" + +"@firebase/auth-interop-types@0.2.4": + version "0.2.4" + resolved "https://registry.yarnpkg.com/@firebase/auth-interop-types/-/auth-interop-types-0.2.4.tgz#176a08686b0685596ff03d7879b7e4115af53de0" + integrity sha512-JPgcXKCuO+CWqGDnigBtvo09HeBs5u/Ktc2GaFj2m01hLarbxthLNm7Fk8iOP1aqAtXV+fnnGj7U28xmk7IwVA== + +"@firebase/auth-types@0.13.0": + version "0.13.0" + resolved "https://registry.yarnpkg.com/@firebase/auth-types/-/auth-types-0.13.0.tgz#ae6e0015e3bd4bfe18edd0942b48a0a118a098d9" + integrity sha512-S/PuIjni0AQRLF+l9ck0YpsMOdE8GO2KU6ubmBB7P+7TJUCQDa3R1dlgYm9UzGbbePMZsp0xzB93f2b/CgxMOg== + +"@firebase/auth@1.11.0": + version "1.11.0" + resolved "https://registry.yarnpkg.com/@firebase/auth/-/auth-1.11.0.tgz#81a4f77b16d97c502e493b2a14a97443e243a2a0" + integrity sha512-5j7+ua93X+IRcJ1oMDTClTo85l7Xe40WSkoJ+shzPrX7OISlVWLdE1mKC57PSD+/LfAbdhJmvKixINBw2ESK6w== + dependencies: + "@firebase/component" "0.7.0" + "@firebase/logger" "0.5.0" + "@firebase/util" "1.13.0" + tslib "^2.1.0" + +"@firebase/component@0.7.0": + version "0.7.0" + resolved "https://registry.yarnpkg.com/@firebase/component/-/component-0.7.0.tgz#3736644fdb6d3572dceae7fdc1c35a8bd3819adc" + integrity sha512-wR9En2A+WESUHexjmRHkqtaVH94WLNKt6rmeqZhSLBybg4Wyf0Umk04SZsS6sBq4102ZsDBFwoqMqJYj2IoDSg== + dependencies: + "@firebase/util" "1.13.0" + tslib "^2.1.0" + +"@firebase/data-connect@0.3.11": + version "0.3.11" + resolved "https://registry.yarnpkg.com/@firebase/data-connect/-/data-connect-0.3.11.tgz#60a7a9649e4aedd005546032466ef9abc0a544c1" + integrity sha512-G258eLzAD6im9Bsw+Qm1Z+P4x0PGNQ45yeUuuqe5M9B1rn0RJvvsQCRHXgE52Z+n9+WX1OJd/crcuunvOGc7Vw== + dependencies: + "@firebase/auth-interop-types" "0.2.4" + "@firebase/component" "0.7.0" + "@firebase/logger" "0.5.0" + "@firebase/util" "1.13.0" + tslib "^2.1.0" + +"@firebase/database-compat@2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@firebase/database-compat/-/database-compat-2.1.0.tgz#c64488d741c6da2ed8dcf02f2e433089dae2f590" + integrity sha512-8nYc43RqxScsePVd1qe1xxvWNf0OBnbwHxmXJ7MHSuuTVYFO3eLyLW3PiCKJ9fHnmIz4p4LbieXwz+qtr9PZDg== + 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.1.0" + +"@firebase/database-types@1.0.16": + version "1.0.16" + resolved "https://registry.yarnpkg.com/@firebase/database-types/-/database-types-1.0.16.tgz#262f54b8dbebbc46259757b3ba384224fb2ede48" + integrity sha512-xkQLQfU5De7+SPhEGAXFBnDryUWhhlFXelEg2YeZOQMCdoe7dL64DDAd77SQsR+6uoXIZY5MB4y/inCs4GTfcw== + dependencies: + "@firebase/app-types" "0.9.3" + "@firebase/util" "1.13.0" + +"@firebase/database@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@firebase/database/-/database-1.1.0.tgz#bdf60f1605079a87ceb2b5e30d90846e0bde294b" + integrity sha512-gM6MJFae3pTyNLoc9VcJNuaUDej0ctdjn3cVtILo3D5lpp0dmUHHLFN/pUKe7ImyeB1KAvRlEYxvIHNF04Filg== + 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.1.0" + +"@firebase/firestore-compat@0.4.0": + version "0.4.0" + resolved "https://registry.yarnpkg.com/@firebase/firestore-compat/-/firestore-compat-0.4.0.tgz#911cf956e489fa8335ed2f2ace14a74909bcd94d" + integrity sha512-4O7v4VFeSEwAZtLjsaj33YrMHMRjplOIYC2CiYsF6o/MboOhrhe01VrTt8iY9Y5EwjRHuRz4pS6jMBT8LfQYJA== + dependencies: + "@firebase/component" "0.7.0" + "@firebase/firestore" "4.9.0" + "@firebase/firestore-types" "3.0.3" + "@firebase/util" "1.13.0" + tslib "^2.1.0" + +"@firebase/firestore-types@3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@firebase/firestore-types/-/firestore-types-3.0.3.tgz#7d0c3dd8850c0193d8f5ee0cc8f11961407742c1" + integrity sha512-hD2jGdiWRxB/eZWF89xcK9gF8wvENDJkzpVFb4aGkzfEaKxVRD1kjz1t1Wj8VZEp2LCB53Yx1zD8mrhQu87R6Q== + +"@firebase/firestore@4.9.0": + version "4.9.0" + resolved "https://registry.yarnpkg.com/@firebase/firestore/-/firestore-4.9.0.tgz#753d73c002b4c0ae639437b049ef0086791a0cf3" + integrity sha512-5zl0+/h1GvlCSLt06RMwqFsd7uqRtnNZt4sW99k2rKRd6k/ECObIWlEnvthm2cuOSnUmwZknFqtmd1qyYSLUuQ== + dependencies: + "@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.0" + "@grpc/proto-loader" "^0.7.8" + tslib "^2.1.0" + +"@firebase/functions-compat@0.4.0": + version "0.4.0" + resolved "https://registry.yarnpkg.com/@firebase/functions-compat/-/functions-compat-0.4.0.tgz#aa63dea248053e9c06904605704662ea550e50ed" + integrity sha512-VPgtvoGFywWbQqtvgJnVWIDFSHV1WE6Hmyi5EGI+P+56EskiGkmnw6lEqc/MEUfGpPGdvmc4I9XMU81uj766/g== + dependencies: + "@firebase/component" "0.7.0" + "@firebase/functions" "0.13.0" + "@firebase/functions-types" "0.6.3" + "@firebase/util" "1.13.0" + tslib "^2.1.0" + +"@firebase/functions-types@0.6.3": + version "0.6.3" + resolved "https://registry.yarnpkg.com/@firebase/functions-types/-/functions-types-0.6.3.tgz#f5faf770248b13f45d256f614230da6a11bfb654" + integrity sha512-EZoDKQLUHFKNx6VLipQwrSMh01A1SaL3Wg6Hpi//x6/fJ6Ee4hrAeswK99I5Ht8roiniKHw4iO0B1Oxj5I4plg== + +"@firebase/functions@0.13.0": + version "0.13.0" + resolved "https://registry.yarnpkg.com/@firebase/functions/-/functions-0.13.0.tgz#91685a59589b3a00f6c48faf383acd28a35800c2" + integrity sha512-2/LH5xIbD8aaLOWSFHAwwAybgSzHIM0dB5oVOL0zZnxFG1LctX2bc1NIAaPk1T+Zo9aVkLKUlB5fTXTkVUQprQ== + dependencies: + "@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.1.0" + +"@firebase/installations-compat@0.2.19": + version "0.2.19" + resolved "https://registry.yarnpkg.com/@firebase/installations-compat/-/installations-compat-0.2.19.tgz#4bc57c8c57d241eeca95900ff3033d6ec3dbcc7c" + integrity sha512-khfzIY3EI5LePePo7vT19/VEIH1E3iYsHknI/6ek9T8QCozAZshWT9CjlwOzZrKvTHMeNcbpo/VSOSIWDSjWdQ== + dependencies: + "@firebase/component" "0.7.0" + "@firebase/installations" "0.6.19" + "@firebase/installations-types" "0.5.3" + "@firebase/util" "1.13.0" + tslib "^2.1.0" + +"@firebase/installations-types@0.5.3": + version "0.5.3" + resolved "https://registry.yarnpkg.com/@firebase/installations-types/-/installations-types-0.5.3.tgz#cac8a14dd49f09174da9df8ae453f9b359c3ef2f" + integrity sha512-2FJI7gkLqIE0iYsNQ1P751lO3hER+Umykel+TkLwHj6plzWVxqvfclPUZhcKFVQObqloEBTmpi2Ozn7EkCABAA== + +"@firebase/installations@0.6.19": + version "0.6.19" + resolved "https://registry.yarnpkg.com/@firebase/installations/-/installations-0.6.19.tgz#93c569321f6fb399f4f1a197efc0053ce6452c7c" + integrity sha512-nGDmiwKLI1lerhwfwSHvMR9RZuIH5/8E3kgUWnVRqqL7kGVSktjLTWEMva7oh5yxQ3zXfIlIwJwMcaM5bK5j8Q== + dependencies: + "@firebase/component" "0.7.0" + "@firebase/util" "1.13.0" + idb "7.1.1" + tslib "^2.1.0" + +"@firebase/logger@0.5.0": + version "0.5.0" + resolved "https://registry.yarnpkg.com/@firebase/logger/-/logger-0.5.0.tgz#a9e55b1c669a0983dc67127fa4a5964ce8ed5e1b" + integrity sha512-cGskaAvkrnh42b3BA3doDWeBmuHFO/Mx5A83rbRDYakPjO9bJtRL3dX7javzc2Rr/JHZf4HlterTW2lUkfeN4g== + dependencies: + tslib "^2.1.0" + +"@firebase/messaging-compat@0.2.23": + version "0.2.23" + resolved "https://registry.yarnpkg.com/@firebase/messaging-compat/-/messaging-compat-0.2.23.tgz#2ca6b36ea238fae4dff53bf85442c4a2af516224" + integrity sha512-SN857v/kBUvlQ9X/UjAqBoQ2FEaL1ZozpnmL1ByTe57iXkmnVVFm9KqAsTfmf+OEwWI4kJJe9NObtN/w22lUgg== + dependencies: + "@firebase/component" "0.7.0" + "@firebase/messaging" "0.12.23" + "@firebase/util" "1.13.0" + tslib "^2.1.0" + +"@firebase/messaging-interop-types@0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@firebase/messaging-interop-types/-/messaging-interop-types-0.2.3.tgz#e647c9cd1beecfe6a6e82018a6eec37555e4da3e" + integrity sha512-xfzFaJpzcmtDjycpDeCUj0Ge10ATFi/VHVIvEEjDNc3hodVBQADZ7BWQU7CuFpjSHE+eLuBI13z5F/9xOoGX8Q== + +"@firebase/messaging@0.12.23": + version "0.12.23" + resolved "https://registry.yarnpkg.com/@firebase/messaging/-/messaging-0.12.23.tgz#71f932a521ac39d9f036175672e37897531010eb" + integrity sha512-cfuzv47XxqW4HH/OcR5rM+AlQd1xL/VhuaeW/wzMW1LFrsFcTn0GND/hak1vkQc2th8UisBcrkVcQAnOnKwYxg== + dependencies: + "@firebase/component" "0.7.0" + "@firebase/installations" "0.6.19" + "@firebase/messaging-interop-types" "0.2.3" + "@firebase/util" "1.13.0" + idb "7.1.1" + tslib "^2.1.0" + +"@firebase/performance-compat@0.2.21": + version "0.2.21" + resolved "https://registry.yarnpkg.com/@firebase/performance-compat/-/performance-compat-0.2.21.tgz#60f04ecb5ff98b5d84a7a932f2e8294aae711c72" + integrity sha512-OQfYRsIQiEf9ez1SOMLb5TRevBHNIyA2x1GI1H10lZ432W96AK5r4LTM+SNApg84dxOuHt6RWSQWY7TPWffKXg== + dependencies: + "@firebase/component" "0.7.0" + "@firebase/logger" "0.5.0" + "@firebase/performance" "0.7.8" + "@firebase/performance-types" "0.2.3" + "@firebase/util" "1.13.0" + tslib "^2.1.0" + +"@firebase/performance-types@0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@firebase/performance-types/-/performance-types-0.2.3.tgz#5ce64e90fa20ab5561f8b62a305010cf9fab86fb" + integrity sha512-IgkyTz6QZVPAq8GSkLYJvwSLr3LS9+V6vNPQr0x4YozZJiLF5jYixj0amDtATf1X0EtYHqoPO48a9ija8GocxQ== + +"@firebase/performance@0.7.8": + version "0.7.8" + resolved "https://registry.yarnpkg.com/@firebase/performance/-/performance-0.7.8.tgz#a3e5ff36070e0f26e59f84fcd8faf7a8ee77c677" + integrity sha512-k6xfNM/CdTl4RaV4gT/lH53NU+wP33JiN0pUeNBzGVNvfXZ3HbCkoISE3M/XaiOwHgded1l6XfLHa4zHgm0Wyg== + dependencies: + "@firebase/component" "0.7.0" + "@firebase/installations" "0.6.19" + "@firebase/logger" "0.5.0" + "@firebase/util" "1.13.0" + tslib "^2.1.0" + web-vitals "^4.2.4" + +"@firebase/remote-config-compat@0.2.19": + version "0.2.19" + resolved "https://registry.yarnpkg.com/@firebase/remote-config-compat/-/remote-config-compat-0.2.19.tgz#10cfd804f65c5ca80a4d40994bc853ca6d1f7307" + integrity sha512-y7PZAb0l5+5oIgLJr88TNSelxuASGlXyAKj+3pUc4fDuRIdPNBoONMHaIUa9rlffBR5dErmaD2wUBJ7Z1a513Q== + dependencies: + "@firebase/component" "0.7.0" + "@firebase/logger" "0.5.0" + "@firebase/remote-config" "0.6.6" + "@firebase/remote-config-types" "0.4.0" + "@firebase/util" "1.13.0" + tslib "^2.1.0" + +"@firebase/remote-config-types@0.4.0": + version "0.4.0" + resolved "https://registry.yarnpkg.com/@firebase/remote-config-types/-/remote-config-types-0.4.0.tgz#91b9a836d5ca30ced68c1516163b281fbb544537" + integrity sha512-7p3mRE/ldCNYt8fmWMQ/MSGRmXYlJ15Rvs9Rk17t8p0WwZDbeK7eRmoI1tvCPaDzn9Oqh+yD6Lw+sGLsLg4kKg== + +"@firebase/remote-config@0.6.6": + version "0.6.6" + resolved "https://registry.yarnpkg.com/@firebase/remote-config/-/remote-config-0.6.6.tgz#50eae3d2d71791d76fb6521971bb646d6628805e" + integrity sha512-Yelp5xd8hM4NO1G1SuWrIk4h5K42mNwC98eWZ9YLVu6Z0S6hFk1mxotAdCRmH2luH8FASlYgLLq6OQLZ4nbnCA== + dependencies: + "@firebase/component" "0.7.0" + "@firebase/installations" "0.6.19" + "@firebase/logger" "0.5.0" + "@firebase/util" "1.13.0" + tslib "^2.1.0" + +"@firebase/storage-compat@0.4.0": + version "0.4.0" + resolved "https://registry.yarnpkg.com/@firebase/storage-compat/-/storage-compat-0.4.0.tgz#a09bd33c262123e7e3ed0cd590b4c6e2ce4a8902" + integrity sha512-vDzhgGczr1OfcOy285YAPur5pWDEvD67w4thyeCUh6Ys0izN9fNYtA1MJERmNBfqjqu0lg0FM5GLbw0Il21M+g== + dependencies: + "@firebase/component" "0.7.0" + "@firebase/storage" "0.14.0" + "@firebase/storage-types" "0.8.3" + "@firebase/util" "1.13.0" + tslib "^2.1.0" + +"@firebase/storage-types@0.8.3": + version "0.8.3" + resolved "https://registry.yarnpkg.com/@firebase/storage-types/-/storage-types-0.8.3.tgz#2531ef593a3452fc12c59117195d6485c6632d3d" + integrity sha512-+Muk7g9uwngTpd8xn9OdF/D48uiQ7I1Fae7ULsWPuKoCH3HU7bfFPhxtJYzyhjdniowhuDpQcfPmuNRAqZEfvg== + +"@firebase/storage@0.14.0": + version "0.14.0" + resolved "https://registry.yarnpkg.com/@firebase/storage/-/storage-0.14.0.tgz#01acb97d413ada7c91de860fb260623468baa25d" + integrity sha512-xWWbb15o6/pWEw8H01UQ1dC5U3rf8QTAzOChYyCpafV6Xki7KVp3Yaw2nSklUwHEziSWE9KoZJS7iYeyqWnYFA== + dependencies: + "@firebase/component" "0.7.0" + "@firebase/util" "1.13.0" + tslib "^2.1.0" + +"@firebase/util@1.13.0": + version "1.13.0" + resolved "https://registry.yarnpkg.com/@firebase/util/-/util-1.13.0.tgz#2e9e7569722a1e3fc86b1b4076d5cbfbfa7265d6" + integrity sha512-0AZUyYUfpMNcztR5l09izHwXkZpghLgCUaAGjtMwXnCg3bj4ml5VgiwqOMOxJ+Nw4qN/zJAaOQBcJ7KGkWStqQ== + dependencies: + tslib "^2.1.0" + +"@firebase/webchannel-wrapper@1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@firebase/webchannel-wrapper/-/webchannel-wrapper-1.0.4.tgz#9d5b4b6f23309260a12856cb574c5e64e6c133f7" + integrity sha512-6m8+P+dE/RPl4OPzjTxcTbQ0rGeRyeTvAi9KwIffBVCiAMKrfXfLZaqD1F+m8t4B5/Q5aHsMozOgirkH1F5oMQ== + +"@grpc/grpc-js@~1.9.0": + version "1.9.15" + resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.9.15.tgz#433d7ac19b1754af690ea650ab72190bd700739b" + integrity sha512-nqE7Hc0AzI+euzUwDAy0aY5hCp10r734gMGRdU+qOPX0XSceI2ULrcXB5U2xSc5VkWwalCj4M7GzCAygZl2KoQ== + dependencies: + "@grpc/proto-loader" "^0.7.8" + "@types/node" ">=12.12.47" + +"@grpc/proto-loader@^0.7.8": + version "0.7.15" + resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.7.15.tgz#4cdfbf35a35461fc843abe8b9e2c0770b5095e60" + integrity sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ== + dependencies: + lodash.camelcase "^4.3.0" + long "^5.0.0" + protobufjs "^7.2.5" + yargs "^17.7.2" + "@hookform/resolvers@^5.1.1": version "5.1.1" resolved "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-5.1.1.tgz" @@ -487,6 +896,59 @@ resolved "https://registry.npmjs.org/@pkgr/core/-/core-0.2.7.tgz" integrity sha512-YLT9Zo3oNPJoBjBc4q8G2mjU4tqIbf5CEOORbUUr48dCD9q3umJ3IPlVqOqDakPfd2HuwccBaqlGhN4Gmr5OWg== +"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" + integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ== + +"@protobufjs/base64@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" + integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== + +"@protobufjs/codegen@^2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb" + integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== + +"@protobufjs/eventemitter@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70" + integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q== + +"@protobufjs/fetch@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45" + integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ== + dependencies: + "@protobufjs/aspromise" "^1.1.1" + "@protobufjs/inquire" "^1.1.0" + +"@protobufjs/float@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" + integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ== + +"@protobufjs/inquire@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089" + integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q== + +"@protobufjs/path@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d" + integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA== + +"@protobufjs/pool@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" + integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw== + +"@protobufjs/utf8@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" + integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== + "@rolldown/pluginutils@1.0.0-beta.11": version "1.0.0-beta.11" resolved "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.11.tgz" @@ -748,6 +1210,13 @@ dependencies: undici-types "~7.8.0" +"@types/node@>=12.12.47", "@types/node@>=13.7.0": + version "24.2.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-24.2.0.tgz#cde712f88c5190006d6b069232582ecd1f94a760" + integrity sha512-3xyG3pMCq3oYCNg7/ZP+E1ooTaGB4cG8JWRsqqOYQdbWNY4zbaV0Ennrd7stjiJEFZCaybcIgpTjJWHRfBSIDw== + dependencies: + undici-types "~7.10.0" + "@types/react-dom@^19.1.2": version "19.1.6" resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.6.tgz" @@ -1949,6 +2418,13 @@ fastq@^1.6.0: dependencies: reusify "^1.0.4" +faye-websocket@0.11.4: + version "0.11.4" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.4.tgz#7f0d9275cfdd86a1c963dc8b65fcc451edcbb1da" + integrity sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g== + dependencies: + websocket-driver ">=0.5.1" + fdir@^6.4.4, fdir@^6.4.6: version "6.4.6" resolved "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz" @@ -1985,6 +2461,40 @@ find-up@^7.0.0: path-exists "^5.0.0" unicorn-magic "^0.1.0" +firebase@^12.0.0: + version "12.0.0" + resolved "https://registry.yarnpkg.com/firebase/-/firebase-12.0.0.tgz#436ee1b97b64265f3e7d3b6b0ce4419cc9fe5ae9" + integrity sha512-KV+OrMJpi2uXlqL2zaCcXb7YuQbY/gMIWT1hf8hKeTW1bSumWaHT5qfmn0WTpHwKQa3QEVOtZR2ta9EchcmYuw== + dependencies: + "@firebase/ai" "2.0.0" + "@firebase/analytics" "0.10.18" + "@firebase/analytics-compat" "0.2.24" + "@firebase/app" "0.14.0" + "@firebase/app-check" "0.11.0" + "@firebase/app-check-compat" "0.4.0" + "@firebase/app-compat" "0.5.0" + "@firebase/app-types" "0.9.3" + "@firebase/auth" "1.11.0" + "@firebase/auth-compat" "0.6.0" + "@firebase/data-connect" "0.3.11" + "@firebase/database" "1.1.0" + "@firebase/database-compat" "2.1.0" + "@firebase/firestore" "4.9.0" + "@firebase/firestore-compat" "0.4.0" + "@firebase/functions" "0.13.0" + "@firebase/functions-compat" "0.4.0" + "@firebase/installations" "0.6.19" + "@firebase/installations-compat" "0.2.19" + "@firebase/messaging" "0.12.23" + "@firebase/messaging-compat" "0.2.23" + "@firebase/performance" "0.7.8" + "@firebase/performance-compat" "0.2.21" + "@firebase/remote-config" "0.6.6" + "@firebase/remote-config-compat" "0.2.19" + "@firebase/storage" "0.14.0" + "@firebase/storage-compat" "0.4.0" + "@firebase/util" "1.13.0" + flat-cache@^4.0.0: version "4.0.1" resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz" @@ -2212,11 +2722,21 @@ hasown@^2.0.2: dependencies: function-bind "^1.1.2" +http-parser-js@>=0.5.1: + version "0.5.10" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.10.tgz#b3277bd6d7ed5588e20ea73bf724fcbe44609075" + integrity sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA== + husky@^9.1.7: version "9.1.7" resolved "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz" integrity sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA== +idb@7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/idb/-/idb-7.1.1.tgz#d910ded866d32c7ced9befc5bfdf36f572ced72b" + integrity sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ== + ignore@^5.2.0: version "5.3.2" resolved "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz" @@ -2752,6 +3272,11 @@ log-update@^6.1.0: strip-ansi "^7.1.0" wrap-ansi "^9.0.0" +long@^5.0.0: + version "5.3.2" + resolved "https://registry.yarnpkg.com/long/-/long-5.3.2.tgz#1d84463095999262d7d7b7f8bfd4a8cc55167f83" + integrity sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA== + loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" @@ -3136,6 +3661,24 @@ prop-types@^15.8.1: object-assign "^4.1.1" react-is "^16.13.1" +protobufjs@^7.2.5: + version "7.5.3" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.5.3.tgz#13f95a9e3c84669995ec3652db2ac2fb00b89363" + integrity sha512-sildjKwVqOI2kmFDiXQ6aEB0fjYTafpEvIBs8tOR8qI4spuL9OPROLVu2qZqi/xgCfsHIwVqlaF8JBjWFHnKbw== + 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" ">=13.7.0" + long "^5.0.0" + proxy-from-env@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz" @@ -3168,6 +3711,11 @@ react-hook-form@^7.55.0, react-hook-form@^7.60.0: resolved "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.60.0.tgz" integrity sha512-SBrYOvMbDB7cV8ZfNpaiLcgjH/a1c7aK0lK+aNigpf4xWLO8q+o4tcvVurv3c4EOyzn/3dCsYt4GKD42VvJ/+A== +react-intersection-observer@^9.16.0: + version "9.16.0" + resolved "https://registry.yarnpkg.com/react-intersection-observer/-/react-intersection-observer-9.16.0.tgz#7376d54edc47293300961010844d53b273ee0fb9" + integrity sha512-w9nJSEp+DrW9KmQmeWHQyfaP6b03v+TdXynaoA964Wxt7mdR3An11z4NNCQgL4gKSK7y1ver2Fq+JKH6CWEzUA== + react-is@^16.13.1: version "16.13.1" resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" @@ -3188,6 +3736,11 @@ react-router@7.6.3: cookie "^1.0.1" set-cookie-parser "^2.6.0" +react-spinners@^0.17.0: + version "0.17.0" + resolved "https://registry.yarnpkg.com/react-spinners/-/react-spinners-0.17.0.tgz#d518913e2192afaae76c5b781929ea3bd7b1910e" + integrity sha512-L/8HTylaBmIWwQzIjMq+0vyaRXuoAevzWoD35wKpNTxxtYXWZp+xtgkfD7Y4WItuX0YvdxMPU79+7VhhmbmuTQ== + "react@^16.8.0 || ^17 || ^18 || ^19", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^18 || ^19", "react@^18.0.0 || ^19.0.0 || ^19.0.0-rc", react@^19.1.0, react@>=18, react@>=18.0.0: version "19.1.0" resolved "https://registry.npmjs.org/react/-/react-19.1.0.tgz" @@ -3322,6 +3875,11 @@ safe-array-concat@^1.1.3: has-symbols "^1.1.0" isarray "^2.0.5" +safe-buffer@>=5.1.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + safe-push-apply@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz" @@ -3700,7 +4258,7 @@ tsconfig-paths@^3.15.0: minimist "^1.2.6" strip-bom "^3.0.0" -tslib@^2.0.3: +tslib@^2.0.3, tslib@^2.1.0, tslib@^2.4.0, tslib@^2.8.0: version "2.8.1" resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz" integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== @@ -3781,6 +4339,11 @@ unbox-primitive@^1.1.0: has-symbols "^1.1.0" which-boxed-primitive "^1.1.1" +undici-types@~7.10.0: + version "7.10.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-7.10.0.tgz#4ac2e058ce56b462b056e629cc6a02393d3ff350" + integrity sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag== + undici-types@~7.8.0: version "7.8.0" resolved "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz" @@ -3836,6 +4399,25 @@ vite-plugin-svgr@^4.3.0: optionalDependencies: fsevents "~2.3.3" +web-vitals@^4.2.4: + version "4.2.4" + resolved "https://registry.yarnpkg.com/web-vitals/-/web-vitals-4.2.4.tgz#1d20bc8590a37769bd0902b289550936069184b7" + integrity sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw== + +websocket-driver@>=0.5.1: + version "0.7.4" + resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.4.tgz#89ad5295bbf64b480abcba31e4953aca706f5760" + integrity sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg== + dependencies: + http-parser-js ">=0.5.1" + safe-buffer ">=5.1.0" + websocket-extensions ">=0.1.1" + +websocket-extensions@>=0.1.1: + version "0.1.4" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" + integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== + which-boxed-primitive@^1.1.0, which-boxed-primitive@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz" @@ -3949,7 +4531,7 @@ yargs-parser@^21.1.1: resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== -yargs@^17.0.0: +yargs@^17.0.0, yargs@^17.7.2: version "17.7.2" resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz" integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==