diff --git a/package.json b/package.json index 1071908..8907e1f 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "@tanstack/react-query": "^5.102.8", "@vis.gl/react-google-maps": "^1.9.0", "axios": "^1.20.0", + "firebase": "^12.19.0", "lucide-react": "^0.468.0", "pretendard": "^1.3.9", "react": "^19.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 27ef4de..a5c8aef 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,6 +20,9 @@ importers: axios: specifier: ^1.20.0 version: 1.20.0 + firebase: + specifier: ^12.19.0 + version: 12.19.0 lucide-react: specifier: ^0.468.0 version: 0.468.0(react@19.2.7) @@ -309,9 +312,246 @@ packages: cpu: [x64] os: [win32] + '@firebase/ai@2.16.0': + resolution: {integrity: sha512-WRVxl58B61Orwf7st7949ZIW2L4huV80Gpaum1z8v2eH+m2xaxWtC8mOjQyVAOirr6O/yf89cBjlPvoyBpBfTg==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app': 0.x + '@firebase/app-types': 0.x + + '@firebase/analytics-compat@0.2.31': + resolution: {integrity: sha512-msTlG9REujk5rjtOHNLngiuPmvaWGQte8ugL4/F6ZCMb+92Ue7SgjSEpNxINkM8ZtTrbGS83j5SZkt0r+M1Tjw==} + peerDependencies: + '@firebase/app': 0.x + '@firebase/app-compat': 0.x + + '@firebase/analytics-types@0.8.5': + resolution: {integrity: sha512-kdnooE7Bis2jEnsqcerRwn/UQpH5D3uvHpku7OdUM9TJN3omlu6iYtbyAQ6XkAJRgJtO0aNf9OOkW8J6D59oCA==} + + '@firebase/analytics@0.10.25': + resolution: {integrity: sha512-oDagV3PHeNXBdxemksZCdj+GmUT19eCnTOcLdQePIIovFXlm3zWy3Gjeaokt9Nqx24kc4ljK8lU0XGcGmmKZ1A==} + peerDependencies: + '@firebase/app': 0.x + + '@firebase/app-check-compat@0.4.7': + resolution: {integrity: sha512-fBb/xSMyIKv1nDmccfzz3IAGBzx/cQOxmZai66rJzifb1hMMkztf824Xx7LhpTUe7HNUbXwY90IvJ66fi8q6yg==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app': 0.x + '@firebase/app-compat': 0.x + + '@firebase/app-check-interop-types@0.3.5': + resolution: {integrity: sha512-qId34pVZ2CXTmtu4ofW5leiI93DvnOvIcr/5GT7MZPw5WXAi6nZoU+g9cNRgl7K90UJSbK0cXxten4meYMPyZg==} + + '@firebase/app-check-types@0.5.5': + resolution: {integrity: sha512-+DF4gzFrlwGFyky38o4T/YN/r51l70yCtJ2HTkwmRj8FCMwPjm4hLH4fQbj6BUvzkiFqliBkitFsRpf1/YZkWA==} + + '@firebase/app-check@0.13.1': + resolution: {integrity: sha512-l8y3dmnhodXks/APAwx4tWqRl3tk8b9874KF1FJyKg1DIU+kMD0l52iz7S9/MW+eK8k6cjJg0G0iJ5KQAsQpow==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app': 0.x + + '@firebase/app-compat@0.5.18': + resolution: {integrity: sha512-77H57WuGEsgrv59HdtuhHG+eQdP8di6myz7O93yW6yTZlR/tLSmsCxCq5vHp6AWWDwSV0EVtKUvizXQiQZVBWA==} + engines: {node: '>=20.0.0'} + + '@firebase/app-types@0.9.6': + resolution: {integrity: sha512-yPLahy7Esfu2w/yme3msVK4xTkDXQqq6szfQn8yVOQpCKiT5GVFjqNpLbuz6NkX0WuTwUidkmPewW3r4xkvpeg==} + + '@firebase/app@0.16.2': + resolution: {integrity: sha512-fyCLPahl3r0Zb7Wzm+JLWcOOH3SaDgAyJzJ8EWIDiv51aNiv+2Pjbpa6myEuP7iXxjmJqrcbVm0GUF7h229T1Q==} + engines: {node: '>=20.0.0'} + + '@firebase/auth-compat@0.6.11': + resolution: {integrity: sha512-L+xp3DTJQrBV08Vt0UhcL/ofUOSjXom7JOJfbT6oas4o7gCrQnTYFKs8wfiuKLmHoo8BxMr5LdgjAs7o6aAsqQ==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app': 0.x + '@firebase/app-compat': 0.x + + '@firebase/auth-interop-types@0.2.6': + resolution: {integrity: sha512-FgwZqDrBqgK0BHI70QTv1v/5wmuDF9f8fsJFvKSxoRlK2PPfSQtZAk2jhXu4pe9BZzFi/e4UYusU/bEQHdf6Qg==} + + '@firebase/auth-types@0.13.2': + resolution: {integrity: sha512-OU+miuoSxIWYN7GT291d2ylVJBL3k/OePo7/JDSoQtkFQoEiGBc4AHuMjj/seqFIsHrqnjrAfRCk4pfufoJolQ==} + peerDependencies: + '@firebase/app-types': 0.x + '@firebase/util': 1.x + + '@firebase/auth@1.13.6': + resolution: {integrity: sha512-MKRLvF72HJ/irNn2fJR0Gv5FOZNtqv1IBeJHRwK8l8pZ/wi9vuUw8ecyCMvQDDNxfS6uW0MWACL5KC4Y8Pp+fA==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app': 0.x + '@react-native-async-storage/async-storage': ^2.2.0 || ^3.0.0 + peerDependenciesMeta: + '@react-native-async-storage/async-storage': + optional: true + + '@firebase/component@0.7.5': + resolution: {integrity: sha512-vuFDcL91Q+2ZuBJkyOh86T4q0B4ffNTDjc/A38tybO56odQABxRTFLTIowCWqAKeIcgo37GowWMVgFF73gD8Qw==} + engines: {node: '>=20.0.0'} + + '@firebase/data-connect@0.7.4': + resolution: {integrity: sha512-su1aGWlzhxb+xtggCUSsufJn1FDa06SBDK71y+fpQ+g2zMhMExik6FUv/odkKzOF/xfWVjabCbWBcjJY3MceDA==} + peerDependencies: + '@firebase/app': 0.x + + '@firebase/database-compat@2.1.7': + resolution: {integrity: sha512-lBq9sJm8MnJINKJnkAKSOj2MbC66xGoSVCcGkPtstl+lkoKEBtD46qHLbuDgW/WbLPoKVm17RIN8BxHj+Z2F2w==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app': 0.x + '@firebase/app-compat': 0.x + peerDependenciesMeta: + '@firebase/app': + optional: true + '@firebase/app-compat': + optional: true + + '@firebase/database-types@1.0.22': + resolution: {integrity: sha512-YAZNXsjY9EQQ+pKw/3ax8n5FgolHC7Qew7EY5RceYdl0R2ZP+kCv1O0DkKlcceue8uQCOreHCNN7PWVFpY1Nug==} + + '@firebase/database@1.1.5': + resolution: {integrity: sha512-/JGpvszLoNXNgzilRXocigGfFF4hbcPA9wN1i1kjJx6oKkXgkHteZYl3lQs1lJX3ETDf6bv7zI15lPMVUp4sAQ==} + engines: {node: '>=20.0.0'} + + '@firebase/firestore-compat@0.4.14': + resolution: {integrity: sha512-HJ2HBNgNPrRsWIJ4E+Kc0u0h1U7HlF7If8AtYjie9HZXlMUmwYSJaXBj9VFm6gkSj5dlKZNcOQ0Ou25CVVG6rA==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app': 0.x + '@firebase/app-compat': 0.x + + '@firebase/firestore-types@3.0.5': + resolution: {integrity: sha512-dbdMAQkMd5dwWc48eupz/Y6/E9ruat3+gY5lhVKscvvT/HnDBEEMzJW38zdKhgdnglZHGk2vUsJMOHAphMHGMA==} + peerDependencies: + '@firebase/app-types': 0.x + '@firebase/util': 1.x + + '@firebase/firestore@4.17.2': + resolution: {integrity: sha512-SiyQEK1dYPOjItFVA+kZGdvOoRAtMebDBvUaSxJPNZMkKcRwYYK2kzWo5UXTZZj523uMxJnkr+KKVySEMme3kQ==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app': 0.x + + '@firebase/functions-compat@0.5.0': + resolution: {integrity: sha512-T3BDIToESZUHt7438wyKYMkRjKg3m1xAIux5fVpNvTRQlDOFLukWniQWBDhJ2znpU9kxMTR6+e31TVo8P15PZw==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app': 0.x + '@firebase/app-compat': 0.x + + '@firebase/functions-types@0.6.5': + resolution: {integrity: sha512-Zc0pURjthHXzSj54ZivCkzKDSV1r/wIpnmHdhq82q2yFFPVoncG/ZJjnVMiANvQfeww/QnElhzODpfwUucVwdA==} + + '@firebase/functions@0.14.0': + resolution: {integrity: sha512-DhuYFr0eMhp+s/PNEk6SiMsYkc00+XVOUeKbrl8MOzQNZI3SKQpqoDR1d+keNDAutwmHRWTUAdXBoVPD+xxVUw==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app': 0.x + + '@firebase/installations-compat@0.2.24': + resolution: {integrity: sha512-8M5nlcWwYt881x83COP2odq5vgf+NgwJh+RMd4LRSv8JI1pxwDfgrDJOERrjTgfC9J5Z0vnQX4b1pdN914e0Zw==} + peerDependencies: + '@firebase/app': 0.x + '@firebase/app-compat': 0.x + + '@firebase/installations-types@0.5.5': + resolution: {integrity: sha512-e9UYcju3puDl1vdrcKIi5dExzHLameOT/Tc61Q48PYwxtsM1NzZh/ikGbdBQTsbRgg0EMZqdPr0/m5ODUBobrg==} + peerDependencies: + '@firebase/app-types': 0.x + + '@firebase/installations@0.6.24': + resolution: {integrity: sha512-Ui52ey8wHoWqkBbXRKJEKYWylI0JZogZmoLS+o8Anh1bxWtK27ZYjLla1UJAAdC5DCKLJ2qAp0VpJOjg8VOX1g==} + peerDependencies: + '@firebase/app': 0.x + + '@firebase/logger@0.5.2': + resolution: {integrity: sha512-J2VO4NFTc0xQFrxV1B/lm5balicm9cwuX2acR9Yn41fN8KgUeQFo+VJV222IqW2FPSXKDu9uo5WdQFWf9TPbYg==} + engines: {node: '>=20.0.0'} + + '@firebase/messaging-compat@0.2.30': + resolution: {integrity: sha512-m1DPT2ET5x0qYqXLoHwKMAyf1mgZZOhuoE6H6/H4OPsp8zSxMIDEFPaW7MaffPJsCA5J7kHzo+BHVNXK4ZoV+w==} + peerDependencies: + '@firebase/app': 0.x + '@firebase/app-compat': 0.x + + '@firebase/messaging-interop-types@0.2.6': + resolution: {integrity: sha512-MVzvkKe2V4H2dHu5oOxRfeKQcfTwWmCgnzsC4V1q3ixun5iiL8riCZ2qI35rDhCL4glPGiu0jHxDbpVNuTKfow==} + + '@firebase/messaging@0.13.3': + resolution: {integrity: sha512-nRXPAp+z0kA3KziJtRY9kktHECvRwaaONzHvislFgllhCwJMscW7icWNQA5IjyP8Uc2+GS/4px8Uz6rx6ftTag==} + peerDependencies: + '@firebase/app': 0.x + + '@firebase/performance-compat@0.2.27': + resolution: {integrity: sha512-O/ozTf/EbChN94Pk7bd1eUC0PAC36726AwsaiJyC0bZzSBWfLGSWASGPH5pebUWXQPJtGxIJYRkkbX5l0Qa+Hw==} + peerDependencies: + '@firebase/app': 0.x + '@firebase/app-compat': 0.x + + '@firebase/performance-types@0.2.5': + resolution: {integrity: sha512-PRzOgB+/M+6AKlEkY8a9xy5Ff5SfZPIh4iShXhn2WAcL/euSbK7bdLqWysHduunNJhGFsXa22Ag3ixqL6rQtYg==} + + '@firebase/performance@0.7.14': + resolution: {integrity: sha512-9PH1XEZVHErxGdbXluvGz4Uyjw4W955H8v7Mv9rHIybRrg5F2Ac2tvf5+mSf5EtnxWNmxrD2WLnvMFaZP4sMrQ==} + peerDependencies: + '@firebase/app': 0.x + + '@firebase/remote-config-compat@0.2.29': + resolution: {integrity: sha512-mY7JtTISK6F4g4T0x3kVepr5cp0NXL7f5yjIUXXGaTrg4qUlFBWRbENaHaqZ78dwmNcLm24h/yPsOVRlDXEXhA==} + peerDependencies: + '@firebase/app': 0.x + '@firebase/app-compat': 0.x + + '@firebase/remote-config-types@0.5.2': + resolution: {integrity: sha512-i8k1omVfoAnaT1ZPv2FFjxMZrATYsO/GnFgHEj5+7fAJLzi8wLnGGv1WK06oEAD6ltrWXSO1HzeNyajn/NjMWw==} + + '@firebase/remote-config@0.9.2': + resolution: {integrity: sha512-Rii93DkXjM+RE/ytHdYa7EIiQLJbdBr+W8EEiqd/vbLCOC+1FdkDuRiumJBp6t3yewHGbdqbpjB3fk3z0cZ+8g==} + peerDependencies: + '@firebase/app': 0.x + + '@firebase/storage-compat@0.4.5': + resolution: {integrity: sha512-vO0tFPxXbKDKdlTu8tYT08S9t9ezUTJYEdLCULpWxWq2aq6zojwN1QmAB+1a50AI/g47GlWUJn1XPncm/PDZsw==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app': 0.x + '@firebase/app-compat': 0.x + + '@firebase/storage-types@0.8.5': + resolution: {integrity: sha512-GEDs5P+rNUfNcS+wxIdOLAHficife2YXtvTJnyi3ssrX11AAtBg+nDUdbYh8vuBzWehVQZPmztGUUnud4L+4yg==} + peerDependencies: + '@firebase/app-types': 0.x + '@firebase/util': 1.x + + '@firebase/storage@0.14.5': + resolution: {integrity: sha512-r2tozN/BlEewLi70tJNUQPzWwbex9GM7NgXZsamHKQrjKEfcR0i4jGgHBKAKA4hbwiPE9eNMb3hcxWnDpeJZwg==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@firebase/app': 0.x + + '@firebase/util@1.15.3': + resolution: {integrity: sha512-c/z/gaIlaaLZEuGbE6sLUuJ61tskg1JghvhcNQzW948ASBinbVBBRnZTC4b4yt4LaEtJQkYlyzqLHcutFwEIvA==} + engines: {node: '>=20.0.0'} + + '@firebase/webchannel-wrapper@1.0.7': + resolution: {integrity: sha512-phBFwieDLvkZGYN9CE9ZFNEIoBVksprzsnCzQejCmCHtgwCXReeuRpoEGN9C4EbhONztv8NRV1tau6Rb9pONwQ==} + '@googlemaps/js-api-loader@2.1.1': resolution: {integrity: sha512-yUpAwksbHrlZIWD49JmveNSfBG4oAK0AwMknfSaPMnP5N7UT8oFRVCqwjGb1XQovi//7KLbPQKZpbofiLGzpDw==} + '@grpc/grpc-js@1.9.16': + resolution: {integrity: sha512-wE4Ut/olIzfKqp631XrG+wbF0v1vWFN4YL9FyXC2LJiG33DsV7PLzURjrCvY/6je2ntdRkeLpPDluzSRGaVltQ==} + 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 + '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -334,6 +574,33 @@ packages: cpu: [x64] os: [linux] + '@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.5': + resolution: {integrity: sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==} + + '@protobufjs/eventemitter@1.1.1': + resolution: {integrity: sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==} + + '@protobufjs/fetch@1.1.1': + resolution: {integrity: sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==} + + '@protobufjs/float@1.0.2': + resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} + + '@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.2': + resolution: {integrity: sha512-b1UQwcEZ4yCnMCD8DAL1VlbvBJE9/IX4FTIp7BG1xYpf29SLazLSrqUkj4w7Y5y7cCVP6E5tcqqcI0xemPkHug==} + '@rolldown/pluginutils@1.0.0-beta.27': resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} @@ -720,6 +987,14 @@ packages: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} @@ -754,6 +1029,17 @@ packages: caniuse-lite@1.0.30001803: resolution: {integrity: sha512-g/uHREV2ZpK9qMalCsWaxmA6ol+DX8GYhuf3T40RKoP+oL7vhRJh8LNt73PCjpnR6l14FzfPrB5Yux4PKm2meg==} + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + + 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==} + combined-stream@1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} @@ -807,6 +1093,9 @@ packages: electron-to-chromium@1.5.388: resolution: {integrity: sha512-Pl/aJaqOOxYxda3vcx1IKSJimwYXHDkEnGn0F+kG2EE68dDtx2uCinaS+Vih8Z91B9t8CSAbiF/HKyWcnXjhzw==} + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + enhanced-resolve@5.24.5: resolution: {integrity: sha512-L1l8TNvomm6UVW5B253AGxQagSQr+vGwhMlrrfRS2qmhx46AMpMVJKQYLvWYbysTMY8VoicOvzHzoHMbyzB+4A==} engines: {node: '>=10.13.0'} @@ -850,6 +1139,10 @@ packages: resolution: {integrity: sha512-sAjhj9ZhOxYCGiNMnZLaucOqf5ZeFnHNoKoAZiD9thhJ0N8RP85qJK759/97C/3L7NzzmGVB5uiX9AUpySZmUQ==} engines: {node: '>=6.0.0'} + faye-websocket@0.11.4: + resolution: {integrity: sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==} + engines: {node: '>=0.8.0'} + fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -859,6 +1152,9 @@ packages: picomatch: optional: true + firebase@12.19.0: + resolution: {integrity: sha512-kwXCLcI0ly2lkwygkbuRx6SsX3DSO96355YrWh9SWZ5ncsxK/y5cirn3sY6nZVSiBVE++2nL6Hchzu1EB8uohQ==} + follow-redirects@1.16.0: resolution: {integrity: sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==} engines: {node: '>=4.0'} @@ -884,6 +1180,10 @@ packages: 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-intrinsic@1.3.0: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} @@ -914,10 +1214,16 @@ packages: resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} engines: {node: '>= 0.4'} + http-parser-js@0.5.10: + resolution: {integrity: sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==} + https-proxy-agent@5.0.1: resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} engines: {node: '>= 6'} + idb@7.1.1: + resolution: {integrity: sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==} + import-fresh@3.3.1: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} @@ -925,6 +1231,10 @@ packages: is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + is-function@1.0.2: resolution: {integrity: sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==} @@ -1025,6 +1335,12 @@ packages: lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + lodash.camelcase@4.3.0: + resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} + + long@5.3.2: + resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} + lower-case@2.0.2: resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} @@ -1115,10 +1431,18 @@ packages: resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} engines: {node: '>= 0.6.0'} + protobufjs@7.6.6: + resolution: {integrity: sha512-dYDWdjSl5RNb7SgPxGQcRU+GtvP7s2fpkrY0r432PcOIaZ0/rBcxEZnQN67iJhFuQiVw754JDoPruPCNdGsbjg==} + engines: {node: '>=12.0.0'} + proxy-from-env@2.1.0: resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==} engines: {node: '>=10'} + re2js@2.8.6: + resolution: {integrity: sha512-xLgQil4kIUCrAzVk9fRSkxkFNwmygLFjVxXrLc65aE1F0+Zsb8rxumFBy4XKyvgMCTL6kilDq3EZ0piE2dP/Dg==} + engines: {node: '>=18.0.0'} + react-dom@19.2.7: resolution: {integrity: sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==} peerDependencies: @@ -1149,6 +1473,10 @@ packages: resolution: {integrity: sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==} engines: {node: '>=0.10.0'} + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -1163,6 +1491,9 @@ packages: version: 0.0.0 engines: {pnpm: '>=11.9.0'} + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + scheduler@0.27.0: resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} @@ -1180,6 +1511,14 @@ packages: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + svg-parser@2.0.4: resolution: {integrity: sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==} @@ -1283,9 +1622,36 @@ packages: yaml: optional: true + web-vitals@4.2.4: + resolution: {integrity: sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==} + + websocket-driver@0.7.5: + resolution: {integrity: sha512-ZL2+3c7kMBdIRCMz6l8jQMHyGVxj+UL+xVk74Ombiciboca8rHa15L86B19E5oh1pL9Ii/uj54gtsIrZGMo6zA==} + engines: {node: '>=0.8.0'} + + websocket-extensions@0.1.4: + resolution: {integrity: sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==} + engines: {node: '>=0.8.0'} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs@17.7.3: + resolution: {integrity: sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==} + engines: {node: '>=12'} + snapshots: '@babel/code-frame@7.29.7': @@ -1480,10 +1846,340 @@ snapshots: '@esbuild/win32-x64@0.25.12': optional: true + '@firebase/ai@2.16.0(@firebase/app-types@0.9.6)(@firebase/app@0.16.2)': + dependencies: + '@firebase/app': 0.16.2 + '@firebase/app-check-interop-types': 0.3.5 + '@firebase/app-types': 0.9.6 + '@firebase/component': 0.7.5 + '@firebase/logger': 0.5.2 + '@firebase/util': 1.15.3 + tslib: 2.8.1 + + '@firebase/analytics-compat@0.2.31(@firebase/app-compat@0.5.18)(@firebase/app@0.16.2)': + dependencies: + '@firebase/analytics': 0.10.25(@firebase/app@0.16.2) + '@firebase/analytics-types': 0.8.5 + '@firebase/app': 0.16.2 + '@firebase/app-compat': 0.5.18 + '@firebase/component': 0.7.5 + '@firebase/util': 1.15.3 + tslib: 2.8.1 + + '@firebase/analytics-types@0.8.5': {} + + '@firebase/analytics@0.10.25(@firebase/app@0.16.2)': + dependencies: + '@firebase/app': 0.16.2 + '@firebase/component': 0.7.5 + '@firebase/installations': 0.6.24(@firebase/app@0.16.2) + '@firebase/logger': 0.5.2 + '@firebase/util': 1.15.3 + tslib: 2.8.1 + + '@firebase/app-check-compat@0.4.7(@firebase/app-compat@0.5.18)(@firebase/app@0.16.2)': + dependencies: + '@firebase/app': 0.16.2 + '@firebase/app-check': 0.13.1(@firebase/app@0.16.2) + '@firebase/app-check-types': 0.5.5 + '@firebase/app-compat': 0.5.18 + '@firebase/component': 0.7.5 + '@firebase/logger': 0.5.2 + '@firebase/util': 1.15.3 + tslib: 2.8.1 + + '@firebase/app-check-interop-types@0.3.5': {} + + '@firebase/app-check-types@0.5.5': {} + + '@firebase/app-check@0.13.1(@firebase/app@0.16.2)': + dependencies: + '@firebase/app': 0.16.2 + '@firebase/component': 0.7.5 + '@firebase/logger': 0.5.2 + '@firebase/util': 1.15.3 + tslib: 2.8.1 + + '@firebase/app-compat@0.5.18': + dependencies: + '@firebase/app': 0.16.2 + '@firebase/component': 0.7.5 + '@firebase/logger': 0.5.2 + '@firebase/util': 1.15.3 + tslib: 2.8.1 + + '@firebase/app-types@0.9.6': + dependencies: + '@firebase/logger': 0.5.2 + + '@firebase/app@0.16.2': + dependencies: + '@firebase/component': 0.7.5 + '@firebase/logger': 0.5.2 + '@firebase/util': 1.15.3 + idb: 7.1.1 + tslib: 2.8.1 + + '@firebase/auth-compat@0.6.11(@firebase/app-compat@0.5.18)(@firebase/app-types@0.9.6)(@firebase/app@0.16.2)': + dependencies: + '@firebase/app': 0.16.2 + '@firebase/app-compat': 0.5.18 + '@firebase/auth': 1.13.6(@firebase/app@0.16.2) + '@firebase/auth-types': 0.13.2(@firebase/app-types@0.9.6)(@firebase/util@1.15.3) + '@firebase/component': 0.7.5 + '@firebase/util': 1.15.3 + tslib: 2.8.1 + transitivePeerDependencies: + - '@firebase/app-types' + - '@react-native-async-storage/async-storage' + + '@firebase/auth-interop-types@0.2.6': {} + + '@firebase/auth-types@0.13.2(@firebase/app-types@0.9.6)(@firebase/util@1.15.3)': + dependencies: + '@firebase/app-types': 0.9.6 + '@firebase/util': 1.15.3 + + '@firebase/auth@1.13.6(@firebase/app@0.16.2)': + dependencies: + '@firebase/app': 0.16.2 + '@firebase/component': 0.7.5 + '@firebase/logger': 0.5.2 + '@firebase/util': 1.15.3 + tslib: 2.8.1 + + '@firebase/component@0.7.5': + dependencies: + '@firebase/util': 1.15.3 + tslib: 2.8.1 + + '@firebase/data-connect@0.7.4(@firebase/app@0.16.2)': + dependencies: + '@firebase/app': 0.16.2 + '@firebase/auth-interop-types': 0.2.6 + '@firebase/component': 0.7.5 + '@firebase/logger': 0.5.2 + '@firebase/util': 1.15.3 + tslib: 2.8.1 + + '@firebase/database-compat@2.1.7(@firebase/app-compat@0.5.18)(@firebase/app@0.16.2)': + dependencies: + '@firebase/component': 0.7.5 + '@firebase/database': 1.1.5 + '@firebase/database-types': 1.0.22 + '@firebase/logger': 0.5.2 + '@firebase/util': 1.15.3 + tslib: 2.8.1 + optionalDependencies: + '@firebase/app': 0.16.2 + '@firebase/app-compat': 0.5.18 + + '@firebase/database-types@1.0.22': + dependencies: + '@firebase/app-types': 0.9.6 + '@firebase/util': 1.15.3 + + '@firebase/database@1.1.5': + dependencies: + '@firebase/app-check-interop-types': 0.3.5 + '@firebase/auth-interop-types': 0.2.6 + '@firebase/component': 0.7.5 + '@firebase/logger': 0.5.2 + '@firebase/util': 1.15.3 + faye-websocket: 0.11.4 + tslib: 2.8.1 + + '@firebase/firestore-compat@0.4.14(@firebase/app-compat@0.5.18)(@firebase/app-types@0.9.6)(@firebase/app@0.16.2)': + dependencies: + '@firebase/app': 0.16.2 + '@firebase/app-compat': 0.5.18 + '@firebase/component': 0.7.5 + '@firebase/firestore': 4.17.2(@firebase/app@0.16.2) + '@firebase/firestore-types': 3.0.5(@firebase/app-types@0.9.6)(@firebase/util@1.15.3) + '@firebase/util': 1.15.3 + tslib: 2.8.1 + transitivePeerDependencies: + - '@firebase/app-types' + + '@firebase/firestore-types@3.0.5(@firebase/app-types@0.9.6)(@firebase/util@1.15.3)': + dependencies: + '@firebase/app-types': 0.9.6 + '@firebase/util': 1.15.3 + + '@firebase/firestore@4.17.2(@firebase/app@0.16.2)': + dependencies: + '@firebase/app': 0.16.2 + '@firebase/component': 0.7.5 + '@firebase/logger': 0.5.2 + '@firebase/util': 1.15.3 + '@firebase/webchannel-wrapper': 1.0.7 + '@grpc/grpc-js': 1.9.16 + '@grpc/proto-loader': 0.7.15 + re2js: 2.8.6 + tslib: 2.8.1 + + '@firebase/functions-compat@0.5.0(@firebase/app-compat@0.5.18)(@firebase/app@0.16.2)': + dependencies: + '@firebase/app': 0.16.2 + '@firebase/app-compat': 0.5.18 + '@firebase/component': 0.7.5 + '@firebase/functions': 0.14.0(@firebase/app@0.16.2) + '@firebase/functions-types': 0.6.5 + '@firebase/util': 1.15.3 + tslib: 2.8.1 + + '@firebase/functions-types@0.6.5': {} + + '@firebase/functions@0.14.0(@firebase/app@0.16.2)': + dependencies: + '@firebase/app': 0.16.2 + '@firebase/app-check-interop-types': 0.3.5 + '@firebase/auth-interop-types': 0.2.6 + '@firebase/component': 0.7.5 + '@firebase/messaging-interop-types': 0.2.6 + '@firebase/util': 1.15.3 + tslib: 2.8.1 + + '@firebase/installations-compat@0.2.24(@firebase/app-compat@0.5.18)(@firebase/app-types@0.9.6)(@firebase/app@0.16.2)': + dependencies: + '@firebase/app': 0.16.2 + '@firebase/app-compat': 0.5.18 + '@firebase/component': 0.7.5 + '@firebase/installations': 0.6.24(@firebase/app@0.16.2) + '@firebase/installations-types': 0.5.5(@firebase/app-types@0.9.6) + '@firebase/util': 1.15.3 + tslib: 2.8.1 + transitivePeerDependencies: + - '@firebase/app-types' + + '@firebase/installations-types@0.5.5(@firebase/app-types@0.9.6)': + dependencies: + '@firebase/app-types': 0.9.6 + + '@firebase/installations@0.6.24(@firebase/app@0.16.2)': + dependencies: + '@firebase/app': 0.16.2 + '@firebase/component': 0.7.5 + '@firebase/util': 1.15.3 + idb: 7.1.1 + tslib: 2.8.1 + + '@firebase/logger@0.5.2': + dependencies: + tslib: 2.8.1 + + '@firebase/messaging-compat@0.2.30(@firebase/app-compat@0.5.18)(@firebase/app@0.16.2)': + dependencies: + '@firebase/app': 0.16.2 + '@firebase/app-compat': 0.5.18 + '@firebase/component': 0.7.5 + '@firebase/messaging': 0.13.3(@firebase/app@0.16.2) + '@firebase/util': 1.15.3 + tslib: 2.8.1 + + '@firebase/messaging-interop-types@0.2.6': {} + + '@firebase/messaging@0.13.3(@firebase/app@0.16.2)': + dependencies: + '@firebase/app': 0.16.2 + '@firebase/component': 0.7.5 + '@firebase/installations': 0.6.24(@firebase/app@0.16.2) + '@firebase/messaging-interop-types': 0.2.6 + '@firebase/util': 1.15.3 + idb: 7.1.1 + tslib: 2.8.1 + + '@firebase/performance-compat@0.2.27(@firebase/app-compat@0.5.18)(@firebase/app@0.16.2)': + dependencies: + '@firebase/app': 0.16.2 + '@firebase/app-compat': 0.5.18 + '@firebase/component': 0.7.5 + '@firebase/logger': 0.5.2 + '@firebase/performance': 0.7.14(@firebase/app@0.16.2) + '@firebase/performance-types': 0.2.5 + '@firebase/util': 1.15.3 + tslib: 2.8.1 + + '@firebase/performance-types@0.2.5': {} + + '@firebase/performance@0.7.14(@firebase/app@0.16.2)': + dependencies: + '@firebase/app': 0.16.2 + '@firebase/component': 0.7.5 + '@firebase/installations': 0.6.24(@firebase/app@0.16.2) + '@firebase/logger': 0.5.2 + '@firebase/util': 1.15.3 + tslib: 2.8.1 + web-vitals: 4.2.4 + + '@firebase/remote-config-compat@0.2.29(@firebase/app-compat@0.5.18)(@firebase/app@0.16.2)': + dependencies: + '@firebase/app': 0.16.2 + '@firebase/app-compat': 0.5.18 + '@firebase/component': 0.7.5 + '@firebase/logger': 0.5.2 + '@firebase/remote-config': 0.9.2(@firebase/app@0.16.2) + '@firebase/remote-config-types': 0.5.2 + '@firebase/util': 1.15.3 + tslib: 2.8.1 + + '@firebase/remote-config-types@0.5.2': {} + + '@firebase/remote-config@0.9.2(@firebase/app@0.16.2)': + dependencies: + '@firebase/app': 0.16.2 + '@firebase/component': 0.7.5 + '@firebase/installations': 0.6.24(@firebase/app@0.16.2) + '@firebase/logger': 0.5.2 + '@firebase/util': 1.15.3 + tslib: 2.8.1 + + '@firebase/storage-compat@0.4.5(@firebase/app-compat@0.5.18)(@firebase/app-types@0.9.6)(@firebase/app@0.16.2)': + dependencies: + '@firebase/app': 0.16.2 + '@firebase/app-compat': 0.5.18 + '@firebase/component': 0.7.5 + '@firebase/storage': 0.14.5(@firebase/app@0.16.2) + '@firebase/storage-types': 0.8.5(@firebase/app-types@0.9.6)(@firebase/util@1.15.3) + '@firebase/util': 1.15.3 + tslib: 2.8.1 + transitivePeerDependencies: + - '@firebase/app-types' + + '@firebase/storage-types@0.8.5(@firebase/app-types@0.9.6)(@firebase/util@1.15.3)': + dependencies: + '@firebase/app-types': 0.9.6 + '@firebase/util': 1.15.3 + + '@firebase/storage@0.14.5(@firebase/app@0.16.2)': + dependencies: + '@firebase/app': 0.16.2 + '@firebase/component': 0.7.5 + '@firebase/util': 1.15.3 + tslib: 2.8.1 + + '@firebase/util@1.15.3': + dependencies: + tslib: 2.8.1 + + '@firebase/webchannel-wrapper@1.0.7': {} + '@googlemaps/js-api-loader@2.1.1': dependencies: '@types/google.maps': 3.66.0 + '@grpc/grpc-js@1.9.16': + dependencies: + '@grpc/proto-loader': 0.7.15 + '@types/node': 24.13.2 + + '@grpc/proto-loader@0.7.15': + dependencies: + lodash.camelcase: 4.3.0 + long: 5.3.2 + protobufjs: 7.6.6 + yargs: 17.7.3 + '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -1506,6 +2202,26 @@ snapshots: '@napi-rs/lzma-linux-x64-gnu@1.5.1': optional: true + '@protobufjs/aspromise@1.1.2': {} + + '@protobufjs/base64@1.1.2': {} + + '@protobufjs/codegen@2.0.5': {} + + '@protobufjs/eventemitter@1.1.1': {} + + '@protobufjs/fetch@1.1.1': + dependencies: + '@protobufjs/aspromise': 1.1.2 + + '@protobufjs/float@1.0.2': {} + + '@protobufjs/path@1.1.2': {} + + '@protobufjs/pool@1.1.0': {} + + '@protobufjs/utf8@1.1.2': {} + '@rolldown/pluginutils@1.0.0-beta.27': {} '@rollup/pluginutils@5.4.0(rollup@4.62.4)': @@ -1783,7 +2499,6 @@ snapshots: '@types/node@24.13.2': dependencies: undici-types: 7.18.2 - optional: true '@types/react-dom@19.2.3(@types/react@19.2.17)': dependencies: @@ -1850,6 +2565,12 @@ snapshots: transitivePeerDependencies: - supports-color + ansi-regex@5.0.1: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + argparse@2.0.1: {} asynckit@0.4.0: {} @@ -1885,6 +2606,18 @@ snapshots: caniuse-lite@1.0.30001803: {} + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + combined-stream@1.0.8: dependencies: delayed-stream: 1.0.0 @@ -1927,6 +2660,8 @@ snapshots: electron-to-chromium@1.5.388: {} + emoji-regex@8.0.0: {} + enhanced-resolve@5.24.5: dependencies: graceful-fs: 4.2.11 @@ -1988,10 +2723,47 @@ snapshots: fast-equals@6.0.2: {} + faye-websocket@0.11.4: + dependencies: + websocket-driver: 0.7.5 + fdir@6.5.0(picomatch@4.0.5): optionalDependencies: picomatch: 4.0.5 + firebase@12.19.0: + dependencies: + '@firebase/ai': 2.16.0(@firebase/app-types@0.9.6)(@firebase/app@0.16.2) + '@firebase/analytics': 0.10.25(@firebase/app@0.16.2) + '@firebase/analytics-compat': 0.2.31(@firebase/app-compat@0.5.18)(@firebase/app@0.16.2) + '@firebase/app': 0.16.2 + '@firebase/app-check': 0.13.1(@firebase/app@0.16.2) + '@firebase/app-check-compat': 0.4.7(@firebase/app-compat@0.5.18)(@firebase/app@0.16.2) + '@firebase/app-compat': 0.5.18 + '@firebase/app-types': 0.9.6 + '@firebase/auth': 1.13.6(@firebase/app@0.16.2) + '@firebase/auth-compat': 0.6.11(@firebase/app-compat@0.5.18)(@firebase/app-types@0.9.6)(@firebase/app@0.16.2) + '@firebase/data-connect': 0.7.4(@firebase/app@0.16.2) + '@firebase/database': 1.1.5 + '@firebase/database-compat': 2.1.7(@firebase/app-compat@0.5.18)(@firebase/app@0.16.2) + '@firebase/firestore': 4.17.2(@firebase/app@0.16.2) + '@firebase/firestore-compat': 0.4.14(@firebase/app-compat@0.5.18)(@firebase/app-types@0.9.6)(@firebase/app@0.16.2) + '@firebase/functions': 0.14.0(@firebase/app@0.16.2) + '@firebase/functions-compat': 0.5.0(@firebase/app-compat@0.5.18)(@firebase/app@0.16.2) + '@firebase/installations': 0.6.24(@firebase/app@0.16.2) + '@firebase/installations-compat': 0.2.24(@firebase/app-compat@0.5.18)(@firebase/app-types@0.9.6)(@firebase/app@0.16.2) + '@firebase/messaging': 0.13.3(@firebase/app@0.16.2) + '@firebase/messaging-compat': 0.2.30(@firebase/app-compat@0.5.18)(@firebase/app@0.16.2) + '@firebase/performance': 0.7.14(@firebase/app@0.16.2) + '@firebase/performance-compat': 0.2.27(@firebase/app-compat@0.5.18)(@firebase/app@0.16.2) + '@firebase/remote-config': 0.9.2(@firebase/app@0.16.2) + '@firebase/remote-config-compat': 0.2.29(@firebase/app-compat@0.5.18)(@firebase/app@0.16.2) + '@firebase/storage': 0.14.5(@firebase/app@0.16.2) + '@firebase/storage-compat': 0.4.5(@firebase/app-compat@0.5.18)(@firebase/app-types@0.9.6)(@firebase/app@0.16.2) + '@firebase/util': 1.15.3 + transitivePeerDependencies: + - '@react-native-async-storage/async-storage' + follow-redirects@1.16.0: {} form-data@4.0.6: @@ -2009,6 +2781,8 @@ snapshots: gensync@1.0.0-beta.2: {} + get-caller-file@2.0.5: {} + get-intrinsic@1.3.0: dependencies: call-bind-apply-helpers: 1.0.2 @@ -2046,6 +2820,8 @@ snapshots: dependencies: function-bind: 1.1.2 + http-parser-js@0.5.10: {} + https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 @@ -2053,6 +2829,8 @@ snapshots: transitivePeerDependencies: - supports-color + idb@7.1.1: {} + import-fresh@3.3.1: dependencies: parent-module: 1.0.1 @@ -2060,6 +2838,8 @@ snapshots: is-arrayish@0.2.1: {} + is-fullwidth-code-point@3.0.0: {} + is-function@1.0.2: {} jiti@2.7.0: {} @@ -2127,6 +2907,10 @@ snapshots: lines-and-columns@1.2.4: {} + lodash.camelcase@4.3.0: {} + + long@5.3.2: {} + lower-case@2.0.2: dependencies: tslib: 2.8.1 @@ -2215,8 +2999,24 @@ snapshots: process@0.11.10: {} + protobufjs@7.6.6: + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/base64': 1.1.2 + '@protobufjs/codegen': 2.0.5 + '@protobufjs/eventemitter': 1.1.1 + '@protobufjs/fetch': 1.1.1 + '@protobufjs/float': 1.0.2 + '@protobufjs/path': 1.1.2 + '@protobufjs/pool': 1.1.0 + '@protobufjs/utf8': 1.1.2 + '@types/node': 24.13.2 + long: 5.3.2 + proxy-from-env@2.1.0: {} + re2js@2.8.6: {} + react-dom@19.2.7(react@19.2.7): dependencies: react: 19.2.7 @@ -2240,6 +3040,8 @@ snapshots: react@19.2.7: {} + require-directory@2.1.1: {} + resolve-from@4.0.0: {} rollup@4.62.4: @@ -2276,6 +3078,8 @@ snapshots: root@git+https://github.com/tanstack/react-query.git#f7c6be35c87beed9796c0aeebe610fcff6c13ccd: {} + safe-buffer@5.2.1: {} + scheduler@0.27.0: {} semver@6.3.1: {} @@ -2289,6 +3093,16 @@ snapshots: source-map-js@1.2.1: {} + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + svg-parser@2.0.4: {} tailwindcss@4.3.3: {} @@ -2315,8 +3129,7 @@ snapshots: typescript@5.9.3: {} - undici-types@7.18.2: - optional: true + undici-types@7.18.2: {} update-browserslist-db@1.2.3(browserslist@4.28.5): dependencies: @@ -2375,4 +3188,34 @@ snapshots: jiti: 2.7.0 lightningcss: 1.32.0 + web-vitals@4.2.4: {} + + websocket-driver@0.7.5: + dependencies: + http-parser-js: 0.5.10 + safe-buffer: 5.2.1 + websocket-extensions: 0.1.4 + + websocket-extensions@0.1.4: {} + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + y18n@5.0.8: {} + yallist@3.1.1: {} + + yargs-parser@21.1.1: {} + + yargs@17.7.3: + 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 diff --git a/public/firebase-messaging-sw.js b/public/firebase-messaging-sw.js new file mode 100644 index 0000000..03c1f20 --- /dev/null +++ b/public/firebase-messaging-sw.js @@ -0,0 +1,17 @@ +importScripts( + "https://www.gstatic.com/firebasejs/12.19.0/firebase-app-compat.js", +); +importScripts( + "https://www.gstatic.com/firebasejs/12.19.0/firebase-messaging-compat.js", +); + +firebase.initializeApp({ + apiKey: "AIzaSyD1DAdlqzDcTWzBaLK220l7CCO7SdXN6YU", + authDomain: "quespot-655f3.firebaseapp.com", + projectId: "quespot-655f3", + storageBucket: "quespot-655f3.firebasestorage.app", + messagingSenderId: "686318748064", + appId: "1:686318748064:web:e7a94717ce0cd715e5e4c5", +}); + +firebase.messaging(); diff --git a/src/App.tsx b/src/App.tsx index 525f489..916a926 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,10 +1,12 @@ import { RouterProvider } from "react-router-dom"; import { router } from "./routes/router"; +import ForegroundNotification from "./components/ForegroundNotification"; function App() { return ( <> + ); } diff --git a/src/components/ForegroundNotification.tsx b/src/components/ForegroundNotification.tsx new file mode 100644 index 0000000..c399b76 --- /dev/null +++ b/src/components/ForegroundNotification.tsx @@ -0,0 +1,112 @@ +import { useEffect, useState } from "react"; +import { useQueryClient } from "@tanstack/react-query"; +import { getMessaging, isSupported, onMessage } from "firebase/messaging"; +import { Bell, X } from "lucide-react"; +import { getAccessToken } from "@/utils/auth"; +import { firebaseApp } from "@/utils/fcm/firebase"; + +type ToastNotification = { + title: string; + body: string; +}; + +export default function ForegroundNotification() { + const queryClient = useQueryClient(); + const [notification, setNotification] = useState( + null, + ); + + useEffect(() => { + let active = true; + let unsubscribe: (() => void) | undefined; + let hideTimer: ReturnType | undefined; + + const startListening = async () => { + try { + if (!(await isSupported()) || !active) return; + + const messaging = getMessaging(firebaseApp); + + unsubscribe = onMessage(messaging, (payload) => { + // 로그아웃 상태에서는 화면에 표시하지 않음 + if (!active || !getAccessToken()) return; + + void queryClient.invalidateQueries({ + queryKey: ["notifications", "list"], + }); + + void queryClient.invalidateQueries({ + queryKey: ["notifications", "unread-count"], + }); + + setNotification({ + title: + payload.notification?.title || + payload.data?.title || + "새로운 알림이 도착했어요", + body: + payload.notification?.body || + payload.data?.body || + "알림함에서 내용을 확인해 주세요.", + }); + + // 새 알림이 오면 다시 5초부터 시작 + if (hideTimer) clearTimeout(hideTimer); + + hideTimer = setTimeout(() => { + setNotification(null); + }, 5000); + }); + } catch (error) { + console.error("실시간 알림 수신 연결에 실패했습니다.", error); + } + }; + + void startListening(); + + return () => { + active = false; + unsubscribe?.(); + + if (hideTimer) clearTimeout(hideTimer); + }; + }, [queryClient]); + + if (!notification) return null; + + return ( +
+
+ + + +
+

+ {notification.title} +

+ +

+ {notification.body} +

+
+ + +
+
+ ); +} diff --git a/src/main.tsx b/src/main.tsx index 5579456..99e30c3 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -4,8 +4,6 @@ import { RouterProvider } from "react-router-dom"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import App from "./App"; -import { router } from "@/routes/router"; - import "pretendard/dist/web/variable/pretendardvariable.css"; import "./styles/global.css"; import "./index.css"; @@ -15,7 +13,7 @@ const queryClient = new QueryClient(); ReactDOM.createRoot(document.getElementById("root")!).render( - + , -); \ No newline at end of file +); diff --git a/src/pages/Auth/LoginPage.tsx b/src/pages/Auth/LoginPage.tsx index 1d3fd4d..3c9d676 100644 --- a/src/pages/Auth/LoginPage.tsx +++ b/src/pages/Auth/LoginPage.tsx @@ -8,13 +8,19 @@ import { PATH } from "@/routes/paths"; import { getSocialLoginUrl, login, type SocialProvider } from "@/apis/auth"; import { saveAuth, saveLoginRedirect } from "@/utils/auth"; import { resolvePostLoginPath } from "@/utils/profile"; +import { connectExistingPush } from "@/utils/fcm/connectExistingPush"; -const inputClass = "type-body2 h-11 w-full rounded-2xl border border-transparent bg-[#eaf5ff] px-4 text-[#252743] outline-none transition placeholder:text-[#8b939e] focus:border-[#5bb5f8]/70 focus:bg-[#f7fbff] focus:ring-3 focus:ring-[#5bb5f8]/15"; +const inputClass = + "type-body2 h-11 w-full rounded-2xl border border-transparent bg-[#eaf5ff] px-4 text-[#252743] outline-none transition placeholder:text-[#8b939e] focus:border-[#5bb5f8]/70 focus:bg-[#f7fbff] focus:ring-3 focus:ring-[#5bb5f8]/15"; export default function LoginPage() { const navigate = useNavigate(); const location = useLocation(); - const routeState = location.state as { email?: string; from?: string; signupComplete?: boolean } | null; + const routeState = location.state as { + email?: string; + from?: string; + signupComplete?: boolean; + } | null; const [email, setEmail] = useState(routeState?.email ?? ""); const [password, setPassword] = useState(""); const [isSubmitting, setIsSubmitting] = useState(false); @@ -29,9 +35,16 @@ export default function LoginPage() { try { const result = await login(email.trim(), password); saveAuth(result.accessToken, result.userId); - navigate(await resolvePostLoginPath(routeState?.from || PATH.HOME), { replace: true }); + await connectExistingPush(); + navigate(await resolvePostLoginPath(routeState?.from || PATH.HOME), { + replace: true, + }); } catch (loginError) { - setError(loginError instanceof Error ? loginError.message : "로그인에 실패했습니다."); + setError( + loginError instanceof Error + ? loginError.message + : "로그인에 실패했습니다.", + ); } finally { setIsSubmitting(false); } @@ -44,45 +57,144 @@ export default function LoginPage() { return (
-
- 여행 가방을 든 Quespot 마스코트 -

Quespot

+
+ 여행 가방을 든 Quespot 마스코트 +

+ Quespot +

- 최선으로 떠나는 특별한 여행
지금 바로 시작해보세요 + 최선으로 떠나는 특별한 여행 +
+ 지금 바로 시작해보세요

-
+
- {routeState?.signupComplete ?

회원가입이 완료됐어요. 로그인해주세요.

: null} - - setEmail(event.target.value)} placeholder="이메일 주소" required type="email" value={email} /> - - setPassword(event.target.value)} placeholder="비밀번호" required type="password" value={password} /> - {error ?

{error}

: null} - + {routeState?.signupComplete ? ( +

+ 회원가입이 완료됐어요. 로그인해주세요. +

+ ) : null} + + setEmail(event.target.value)} + placeholder="이메일 주소" + required + type="email" + value={email} + /> + + setPassword(event.target.value)} + placeholder="비밀번호" + required + type="password" + value={password} + /> + {error ? ( +

+ {error} +

+ ) : null} +
-