From 5d7dddc321248d3f847d58506c8ce0977320f224 Mon Sep 17 00:00:00 2001 From: Dao Ho <84757503+Dao-Ho@users.noreply.github.com> Date: Mon, 2 Dec 2024 09:30:21 -0500 Subject: [PATCH 1/3] Scrum 24: Home Page (#76) Co-authored-by: Ryan Saperstein --- backend/supabase/seed.sql | 4 +- frontend/.prettierrc.json | 18 +- frontend/App.js | 71 ++-- .../__test__/homeScreen/homeScreen.test.tsx | 48 +-- frontend/app.json | 68 +-- frontend/assets/images/celebration.png | Bin 0 -> 606 bytes .../assets/images/chevron-right-black.png | Bin 0 -> 413 bytes frontend/assets/images/construction.png | Bin 0 -> 1013 bytes frontend/assets/images/design_services.png | Bin 0 -> 891 bytes frontend/assets/images/handyman.png | Bin 0 -> 1017 bytes frontend/assets/images/house.png | Bin 0 -> 680 bytes frontend/assets/images/landscape.png | Bin 0 -> 535 bytes frontend/assets/images/maps_home_work.png | Bin 0 -> 710 bytes frontend/assets/images/money-success.png | Bin 0 -> 947 bytes frontend/assets/images/search-white.png | Bin 0 -> 862 bytes frontend/assets/images/topic.png | Bin 0 -> 477 bytes frontend/eas.json | 36 +- frontend/eslint.config.mjs | 122 +++--- frontend/package-lock.json | 392 ++++++++++-------- frontend/package.json | 1 + frontend/src/components/Button.tsx | 13 +- frontend/src/components/Card.tsx | 13 +- frontend/src/components/ProgressBar.tsx | 5 +- frontend/src/components/SearchBar.tsx | 150 +++---- frontend/src/components/SideBySide.tsx | 10 +- frontend/src/components/Tag.tsx | 25 +- frontend/src/components/TextField.tsx | 327 ++++++--------- frontend/src/components/WideButton.tsx | 87 ++++ frontend/src/components/carousel.tsx | 58 +-- frontend/src/constants.ts | 8 +- .../home/components/BottomSheetComponent.tsx | 76 ++++ .../home/components/InvestmentContainer.tsx | 72 ++++ .../home/components/RecentlyViewedCards.tsx | 111 +++++ .../src/screens/home/components/StatusTag.tsx | 102 +++++ .../home/{ => components}/portfolioValue.tsx | 28 +- .../home/{ => components}/welcomeBlock.tsx | 84 ++-- frontend/src/screens/home/home.tsx | 144 ++----- frontend/src/screens/home/styles.ts | 24 +- frontend/src/screens/login/WelcomeScreen.tsx | 25 +- .../login/components/RadioButtonComponent.tsx | 10 +- .../signup_flow/ConnectAccountsScreen.tsx | 32 +- .../login/signup_flow/EmailInputScreen.tsx | 43 +- .../login/signup_flow/PasswordInputScreen.tsx | 43 +- .../login/signup_flow/UserDetailsScreen.tsx | 48 +-- .../src/screens/portfolio/PortfolioScreen.tsx | 229 +++++----- .../portfolio/components/PortfolioDetails.tsx | 104 +++-- .../portfolio/components/PortfolioItem.tsx | 138 +++--- .../components/PortfolioUpdateCard.tsx | 56 +-- .../components/PortfolioUpdateText.tsx | 23 +- .../src/screens/profile/ProfileScreen.tsx | 122 +++--- .../profile/components/NotificationButton.tsx | 49 ++- .../components/ProfilePageNavigator.tsx | 49 ++- .../screens/project/ProjectImagesScreen.tsx | 117 +++--- .../src/screens/project/ProjectMapScreen.tsx | 31 +- .../src/screens/project/ProjectScreen.tsx | 297 +++++++------ frontend/src/services/investor.ts | 14 +- frontend/src/types/contributor.ts | 12 +- frontend/src/types/env.d.ts | 10 +- frontend/tailwind.config.js | 1 + frontend/tsconfig.json | 8 +- frontend/yarn.lock | 381 +++++++++-------- 61 files changed, 2225 insertions(+), 1714 deletions(-) create mode 100644 frontend/assets/images/celebration.png create mode 100644 frontend/assets/images/chevron-right-black.png create mode 100644 frontend/assets/images/construction.png create mode 100644 frontend/assets/images/design_services.png create mode 100644 frontend/assets/images/handyman.png create mode 100644 frontend/assets/images/house.png create mode 100644 frontend/assets/images/landscape.png create mode 100644 frontend/assets/images/maps_home_work.png create mode 100644 frontend/assets/images/money-success.png create mode 100644 frontend/assets/images/search-white.png create mode 100644 frontend/assets/images/topic.png create mode 100644 frontend/src/components/WideButton.tsx create mode 100644 frontend/src/screens/home/components/BottomSheetComponent.tsx create mode 100644 frontend/src/screens/home/components/InvestmentContainer.tsx create mode 100644 frontend/src/screens/home/components/RecentlyViewedCards.tsx create mode 100644 frontend/src/screens/home/components/StatusTag.tsx rename frontend/src/screens/home/{ => components}/portfolioValue.tsx (77%) rename frontend/src/screens/home/{ => components}/welcomeBlock.tsx (91%) diff --git a/backend/supabase/seed.sql b/backend/supabase/seed.sql index 9cd0b87..eeedb5b 100644 --- a/backend/supabase/seed.sql +++ b/backend/supabase/seed.sql @@ -108,8 +108,8 @@ INSERT INTO developers (id, name, description, premise, street, locality, state, INSERT INTO developers (id, name, description, premise, street, locality, state, zipcode) VALUES ('c2128c81-e4db-4695-8be7-089f12d5ea46', 'Developer 1', 'Developer 1 description', '7', 'Speare Pl', 'Boston', 'MA', '02115'); INSERT INTO developers (id, name, description, premise, street, locality, state, zipcode) VALUES ('56ebee48-d844-4fcd-aa58-fb71688c3e81', 'Arav', 'Developer for Generate', '7', 'Speare Pl', 'Boston', 'MA', '02115'); -INSERT INTO projects (id, developer_id, title, description, completed, funding_goal_cents, milestone, completion_date, premise, street, locality, state, zipcode, coordinates) VALUES ('c3733692-5a86-441f-8ad0-9c32c648bb72', '56ebee48-d844-4fcd-aa58-fb71688c3e81', 'Bowser Castle', 'A big fiery castle sitting on prime real estate', 'FALSE', '100000000', 'Land Control Secured', 'December 2027', '7', 'Speare Pl', 'Boston', 'MA', '02115', ST_GeogFromText('SRID=4326;POINT(42.34135 -71.09007)')); -INSERT INTO projects (id, developer_id, title, description, completed, funding_goal_cents, milestone, completion_date, premise, street, locality, state, zipcode, coordinates) VALUES ('d09c8f0f-13d3-4336-92e9-b0b2c8bce570', '56ebee48-d844-4fcd-aa58-fb71688c3e81', 'Spongebob Pineapple', 'A pineapple under the sea', 'TRUE', '18000000', 'Construction Completed', 'October 2025', '716', 'Columbus Ave', 'Boston', 'MA', '02120', ST_GeogFromText('SRID=4326;POINT(42.33772 -71.08530)')); +INSERT INTO projects (id, developer_id, title, description, completed, funding_goal_cents, milestone, premise, street, locality, state, zipcode, coordinates) VALUES ('c3733692-5a86-441f-8ad0-9c32c648bb72', '56ebee48-d844-4fcd-aa58-fb71688c3e81', 'Bowser Castle', 'A big fiery castle sitting on prime real estate', 'FALSE', '100000000', 'Land Control Secured', '7', 'Speare Pl', 'Boston', 'MA', '02115', ST_GeogFromText('SRID=4326;POINT(42.34135 -71.09007)')); +INSERT INTO projects (id, developer_id, title, description, completed, funding_goal_cents, milestone, premise, street, locality, state, zipcode, coordinates) VALUES ('d09c8f0f-13d3-4336-92e9-b0b2c8bce570', '56ebee48-d844-4fcd-aa58-fb71688c3e81', 'Spongebob Pineapple', 'A pineapple under the sea', 'TRUE', '18000000', 'Construction Complete', '716', 'Columbus Ave', 'Boston', 'MA', '02120', ST_GeogFromText('SRID=4326;POINT(42.33772 -71.08530)')); INSERT INTO project_images (project_id, image_url) VALUES ('c3733692-5a86-441f-8ad0-9c32c648bb72', 'https://cdn2.thecatapi.com/images/MTk3OTMzMg.jpg'); INSERT INTO project_images (project_id, image_url) VALUES ('c3733692-5a86-441f-8ad0-9c32c648bb72', 'https://cdn2.thecatapi.com/images/MjA1MTYzNg.jpg'); diff --git a/frontend/.prettierrc.json b/frontend/.prettierrc.json index d0eb00b..95f5249 100644 --- a/frontend/.prettierrc.json +++ b/frontend/.prettierrc.json @@ -1,9 +1,9 @@ -{ - "semi": true, - "tabWidth": 2, - "printWidth": 100, - "singleQuote": true, - "trailingComma": "all", - "jsxSingleQuote": true, - "bracketSpacing": true -} +{ + "semi": true, + "tabWidth": 2, + "printWidth": 100, + "singleQuote": true, + "trailingComma": "all", + "jsxSingleQuote": true, + "bracketSpacing": true +} diff --git a/frontend/App.js b/frontend/App.js index 955acb3..dea4562 100644 --- a/frontend/App.js +++ b/frontend/App.js @@ -12,46 +12,45 @@ SplashScreen.preventAutoHideAsync(); // Navigates user to the log in screen if seesion is not found (i.e. user not logged in) function RootNavigator() { - const { session, isLoading } = useAuth(); - if (isLoading) { - return null; // or some loading screen (maybe we make in future?) - } - return session ? : ; + const { session, isLoading } = useAuth(); + if (isLoading) { + return null; // or some loading screen (maybe we make in future?) + } + return session ? : ; } export default function App() { - const [loaded, error] = useFonts({ - 'Nunito-Black': require('./assets/fonts/nunito/Nunito-Black.ttf'), - 'Nunito-BoldItalic': require('./assets/fonts/nunito/Nunito-BoldItalic.ttf'), - 'Nunito-Bold': require('./assets/fonts/nunito/Nunito-Bold.ttf'), - 'Nunito-ExtraBold': require('./assets/fonts/nunito/Nunito-ExtraBold.ttf'), - 'Nunito-Regular': require('./assets/fonts/nunito/Nunito-Regular.ttf'), - 'Inter-Bold': require('./assets/fonts/inter/Inter_18pt-Bold.ttf'), - 'Inter-Regular': require('./assets/fonts/inter/Inter_18pt-Regular.ttf'), - 'SourceSans3-Bold': require('./assets/fonts/sourceSans3/SourceSans3-Bold.ttf'), - 'SourceSans3-Medium': require('./assets/fonts/sourceSans3/SourceSans3-Medium.ttf'), - 'SourceSans3-SemiBold': require('./assets/fonts/sourceSans3/SourceSans3-SemiBold.ttf'), - }); - - const queryClient = new QueryClient(); + const [loaded, error] = useFonts({ + 'Nunito-Black': require('./assets/fonts/nunito/Nunito-Black.ttf'), + 'Nunito-BoldItalic': require('./assets/fonts/nunito/Nunito-BoldItalic.ttf'), + 'Nunito-Bold': require('./assets/fonts/nunito/Nunito-Bold.ttf'), + 'Nunito-ExtraBold': require('./assets/fonts/nunito/Nunito-ExtraBold.ttf'), + 'Nunito-Regular': require('./assets/fonts/nunito/Nunito-Regular.ttf'), + 'Inter-Bold': require('./assets/fonts/inter/Inter_18pt-Bold.ttf'), + 'Inter-Regular': require('./assets/fonts/inter/Inter_18pt-Regular.ttf'), + 'SourceSans3-Bold': require('./assets/fonts/sourceSans3/SourceSans3-Bold.ttf'), + 'SourceSans3-Medium': require('./assets/fonts/sourceSans3/SourceSans3-Medium.ttf'), + 'SourceSans3-SemiBold': require('./assets/fonts/sourceSans3/SourceSans3-SemiBold.ttf'), + }); - useEffect(() => { - if (loaded || error) { - SplashScreen.hideAsync(); - } - }, [loaded, error]); + const queryClient = new QueryClient(); - if (!loaded && !error) { - return null; + useEffect(() => { + if (loaded || error) { + SplashScreen.hideAsync(); } - return ( - - - - - - - - - ); + }, [loaded, error]); + + if (!loaded && !error) { + return null; + } + return ( + + + + + + + + ); } diff --git a/frontend/__test__/homeScreen/homeScreen.test.tsx b/frontend/__test__/homeScreen/homeScreen.test.tsx index d1cf7e8..cb81eda 100644 --- a/frontend/__test__/homeScreen/homeScreen.test.tsx +++ b/frontend/__test__/homeScreen/homeScreen.test.tsx @@ -1,24 +1,24 @@ -import React from 'react'; -import renderer from 'react-test-renderer'; -import { describe, expect, test } from '@jest/globals'; -import { HomeScreen } from '../../src/screens/home/home'; - -describe('Home screen', () => { - test('Test that image is on home screen', () => { - // ARRANGE - // Using any since its irrelevant and this avoids type checks - // (this avoids needing to instantiate a real navigation object) - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const mockNavigation: any = null; - - // ACT - let root; - renderer.act(() => { - root = renderer.create(); - }); - - // ASSERT - root.root.findByType('Image'); // This will throw an error if there is not exactly one image, so we know the image was rendered if the test succeeds - expect(root.root.findByType('Text').props.children).toBe('Dummy page'); - }); -}); +import React from 'react'; +import renderer from 'react-test-renderer'; +import { describe, expect, test } from '@jest/globals'; +import { HomeScreen } from '../../src/screens/home/home'; + +describe('Home screen', () => { + test('Test that image is on home screen', () => { + // ARRANGE + // Using any since its irrelevant and this avoids type checks + // (this avoids needing to instantiate a real navigation object) + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const mockNavigation: any = null; + + // ACT + let root; + renderer.act(() => { + root = renderer.create(); + }); + + // ASSERT + root.root.findByType('Image'); // This will throw an error if there is not exactly one image, so we know the image was rendered if the test succeeds + expect(root.root.findByType('Text').props.children).toBe('Dummy page'); + }); +}); diff --git a/frontend/app.json b/frontend/app.json index 515cb78..6a6ef39 100644 --- a/frontend/app.json +++ b/frontend/app.json @@ -1,34 +1,34 @@ -{ - "expo": { - "name": "3stones", - "slug": "frontend", - "version": "0.1.0", - "orientation": "portrait", - "icon": "./assets/images/icon.png", - "userInterfaceStyle": "light", - "splash": { - "image": "./assets/images/splash.png", - "resizeMode": "contain", - "backgroundColor": "#ffffff" - }, - "ios": { - "supportsTablet": true, - "bundleIdentifier": "com.generate.3stones" - }, - "android": { - "adaptiveIcon": { - "foregroundImage": "./assets/images/adaptive-icon.png", - "backgroundColor": "#ffffff" - } - }, - "web": { - "favicon": "./assets/images/favicon.png" - }, - "extra": { - "eas": { - "projectId": "27b7d706-8b3c-45f8-ba59-ae05df33c4de" - } - }, - "plugins": ["expo-font"] - } -} +{ + "expo": { + "name": "3stones", + "slug": "frontend", + "version": "0.1.0", + "orientation": "portrait", + "icon": "./assets/images/icon.png", + "userInterfaceStyle": "light", + "splash": { + "image": "./assets/images/splash.png", + "resizeMode": "contain", + "backgroundColor": "#ffffff" + }, + "ios": { + "supportsTablet": true, + "bundleIdentifier": "com.generate.3stones" + }, + "android": { + "adaptiveIcon": { + "foregroundImage": "./assets/images/adaptive-icon.png", + "backgroundColor": "#ffffff" + } + }, + "web": { + "favicon": "./assets/images/favicon.png" + }, + "extra": { + "eas": { + "projectId": "27b7d706-8b3c-45f8-ba59-ae05df33c4de" + } + }, + "plugins": ["expo-font"] + } +} diff --git a/frontend/assets/images/celebration.png b/frontend/assets/images/celebration.png new file mode 100644 index 0000000000000000000000000000000000000000..3c565c73a356a3863004fcc4f96f6f02f1346af2 GIT binary patch literal 606 zcmV-k0-^nhP)jK~#7F?U;>i z!Y~kpFI5L%1V&&3JVG}h8!$pW0^Oh^bc3(~Y>*LPgV%E%)Fe3mN$lWA`6R1qV&J{= zo&ShdR#s*KK*{aIZA(joMGO2>FU|xD-l5APO_V(o7s?5r95wq8(s$G9ccY2CQ3Q&jxbmN`)}y_p`-U7eBU&kgkCEbbpp^JVmfwBbQiz{@Vwj8i z9ZFoQ;vcW}HnaiSEAh^%zH|C`aEM^+A*jwN0MMplNrZ~7=Rf>MBP{!5B1eioVt z?I=K8HsVbzUA)Lre3K?>cBo-lTri;~k^#M4xZxS&;(`%1k(4ItLpWE+SBn>LGiUf?|)(GdnbJZedgQfGv$b31YTE+ so)rBDEVd-Qi2ZQ8aGZx^prwfgF}}M_)$E)e-c@Naz>smjv*C{Z*TARRS6Vfxp3<)%e5nG1UQ%{ z^UUy3VCHD_@o3~xU_QZ6#lj|0<2LJA-v!H{m4CIqx@YZW0h$K}4SRo0Km4WsaI literal 0 HcmV?d00001 diff --git a/frontend/assets/images/construction.png b/frontend/assets/images/construction.png new file mode 100644 index 0000000000000000000000000000000000000000..b93c625c179b56dace25f20fe31b43b793d57a3c GIT binary patch literal 1013 zcmVp%iBodrwMtE zR33=Q10y=}JBJHPvr>CJE)>X*3%hP$CxZu;$V#4r60&bYK8_C=tOU3qf2&@r0uOdW zyYlAh%%F$fQovY%5qYs9`K2EwQ#}_oCSC_%7Cph23arU92r)Y?AI>kX>!uZC7l$59?6I?aEzKmj zBV)zMag1wH6*nSqpqkt1m8zgdfCqF3gEu0AH)&uT?0Tiv^q)ts8;}6yHj93RmwZXp z#9a|~-BgMBhL*5S5Q|jXA%DWym?}U`pv{dc5wU;^bKha5wiA(=Jcl-ohPb$gHvwH* zjOV`aLoaHLVSJdh!A{6?B-R025g2%15~evL&tX)^Vi7zodW1ey%`-@qPRVmPc_!w# z3i2G*4>U5QCC}}6#fA*X?13!gW4rSe+ZLGwxF8=Rt%%eDT#}EGMntL@NK2j)jrAraU0$k^LS0aoA^s7j@5RoXL-xW5i2yGS;ug&}1 z9+-5oJUb27YrbqupGNVWzh=}~Z)4PoE4U;GV5$!d&Kt8t5sXN=Xaz6|?(Zw{bOi1r%M(8Rr6c4J@&1BCpEP)K~#7F?ODxr z+CUHv^*j0&dzFO zbJ6$SKBWEAe7m#rvkqH6;c$3J({x7>;CV6M zBgze4)8%qG(~eaWz()oU{wE%LrKTN7e5y+#Ulg9VU#NZpi7%S*DguJ=2DL~ygf~!; z@Dfl6ZxBSnBfNo^M3>}`ScQk~KcIXob^j+23q}f{?}TLG8F%yf{88%g&ef2w(1t9+ zuU4yMyWOrwqtO)(-k{Lj!~0}796qBxBLSPuW{dHi{NPF$jK||1`v0&sI(GmQCobX5 zJD%^*@1-=SB4Jr1KLN`m zAByh~f_EnohMY*04s0)w#BRUe-%=<6O!!=?@*ODF`88QcSgehfgx9i31QMR0RDB|W zNwfTeEO^Erg2}tJStqhv8y^XkSr+|(V5>#@Je$p)pmLu{hb$NLq~}V(r)b>gr( zLipMdZ4d!QSwRa(S2VMz5p?DFs2t=+vul7}JK4I|I zhxklY93DGJotiSE8dwE`ANh`-iKed&Y88rgQZ|8d&wFF(uU01&fd(uNhYI)QO4RY{ zyFv~X2`_;L&1EHa!a+V0UPw=!ah2~@B1-4U6FWiRQv$7jBwQa(Zd$t9(FZ>rhE4ye7Rv=dZAct$LN;4oO3 zPpFgp7y`9pcn^u78w!cQPHKxu0~v+{+kF13is!`dSJYkCxn60}qD70#;4gv$b*Ehc RiT(fp002ovPDHLkV1g(riE#h` literal 0 HcmV?d00001 diff --git a/frontend/assets/images/handyman.png b/frontend/assets/images/handyman.png new file mode 100644 index 0000000000000000000000000000000000000000..3b68234d1f6416a2e91715d4aac559ad873e38d9 GIT binary patch literal 1017 zcmVf)ButPhec8vV8)eg3fS)>=7uP0?0S-Eq+3) zl}6gdZus8gp%a6doUP0 zk`P7@ILI@^o^XwPrBWHEJ-Z1QQ7etKOm^V#s0ERA)_OLQi<*2G|>s z+p{`&H}GVts5m~P`Fy@QJw1KFC@eAJOT3z*T%-MwY@VH+(QG!G3hce1Eq~u2KUB}p z&!^}kQC|k_MlFfXncz}ybtw!T*dMAdVhVs|YFVd~lsr6rX9}~X$Q2}j;VUACe8vWz zTL_z7ki9U7_^aCu7Qm2-u#x8j4W`9On&7_Sd6e2-=pscc&BRsZ7-&N-dG(}*@&a3UZnq*& zcneVW^R6wii2OT|KoMSv%!51=YDvj6*e2WNKF9-N0Y2nSkX)^Vh!6=VNtw9@C|xK67M&ofdgQBEl%32zlPmn-UX5 zJaZj+!X+Y;2a1y4?dS6V``5_659EowJP{ij4i811!EFk7B6BlgnnFLw6H@X!6cEwW z-gkXQQK6X7Dyu-=XGJ!YfP_=DmkZ^zOmqH-BTB}9p2L?N_>g{o00000NkvXXu0mjfkbuw; literal 0 HcmV?d00001 diff --git a/frontend/assets/images/house.png b/frontend/assets/images/house.png new file mode 100644 index 0000000000000000000000000000000000000000..877d368ce8e22ed7bfd03d2f8db9c87e50cb275c GIT binary patch literal 680 zcmV;Z0$2TsP)p1WKfA~C{ zH+tRH8Blzu=F)0Us>es5fdd99bXy0CtPhfpj1rq1V*s8xDA5mlD?5%CgqK|Goq9xwgur2?X1W1!V#0wI_j*1xLUuF4S)D5yjJ z?CrdJ3)5e}|Hz!uJ5c!1+DC_e!XrXFnpd?(Z_zGoqb{=HEnp&;D=otop@o9K0T{^Q zwA-k6agy=WvKmI)=ws%|3&?z&UW8JHmFZeCEX1|X{pF%P|lS6GO5IY30w|*D=TslSs&*dmU^)uq0%v=e6!r*axrp|3-ZaN1PL|sOK@vy4S(-gOdkr z>Uo~$-%%9Zd7c-+9cMpS?|{-Zt@^QJ=%B`KJL-7_c(nd!!pg*)daire(0=1O82zw35M}T|M;Qzh7yP|oX6AY)QYK<0OKAr7oGQ|mV|;J z_`vdlSF9+u*Jfuc0m?GOLLo`U&Au)Zzhj|L0x!)zorz8oj#2*UB1zO_g^fFKTdG_LrHbsyKWu=tM4UT!M>FB=yIxd(w)N`}N;HrFy>G`O z+haNKp;;>sQS~X_Np%Jid%^VPGs;RtSA6NfAh8|Do}K;xCI`W z6saixnnOmv6Yjb_IQnl|;5&;twMgaQU6ltsTrt=jQtE;9avv!A4ZVXS zotmf8^K<)vPe23o5gQ^{O|Hwtfh24AFv{Fm#;egyvx67HvN0cK>sP=!kTxr8AY8YH zi5ttS{vYtMA(S?DA25a82euXKK-z4j1NuXUe=P#79yUi8abY{}A5XwXh)KIDBk5!D su>pJpe-i6Gp825^kw-KZi^Y--4`8C*=drzO=>Px#07*qoM6N<$f{xoiF8}}l literal 0 HcmV?d00001 diff --git a/frontend/assets/images/money-success.png b/frontend/assets/images/money-success.png new file mode 100644 index 0000000000000000000000000000000000000000..6db211945360453f4cc255ddfa21d47f65fd5582 GIT binary patch literal 947 zcmV;k15EshP)G19PB(Oyj5u2qk(vY4-=|?9s1QCE@Oqp1sP$adaIpHy91KUgCxRjLN`yY(I*%2KiMZ=Kd%^b zc)&o!$Owz~QsN#qNFsd#OO48RhAcOJH@52(_P$L0-0|T#Et>W0pyL!u%OHt#8fBbi zz1I|&7k6#moku4$KA@Ift6Gqy-h zpK%KAq2Fsk$pEuzn>?L5zf(d`ypYSCQtCSE7WPjeMq<%InR>-0Bcl3$8yT~^g}rYO z1F@-5vtF^dsHlv+glHM*;kD2tMzR{onCb4NY=pL+_!e<8Hx%e>;9^$D6eU5Y-2g93 z^-7)rs|Kog1PwI_JuT$~y2Wyn18(@oNgurjNoHz*K-2^w{Jdj~L8MMD3~4Q7Ha_Jz zH%^2*h!(NCRoaaDS%!Eic0EEtkxHKc=Mb(5pv~ zM6Ic>SDLi=htPkDe!&h=^pmZ+%@2;pfEYtr`(& zOEnR3&yF$y|IEBD7a4~H1ZpS~y6iSk?}lmt{uj?|?m4M@@2UGQ)d1|!Ufew=_4{0O zq#6iZprQh}20E5*pf3sE_05K#r~qy;t@E6|piHC)sT{t>IHydEA<&|iNmB&+ zl%xpcb4tmH+8GrlMWD`eJi3%IB8}&GM^iKPJOtr+ST+}@ILJ3znG0_zKUbdPUC#Y9 zwm|M84xZE3lpkLm2dV{3_p*8wsJEqBKzO>JWf>IV<=rB$IY}VAfHnFiAHvJKCAxMR z5f_ar671eSX5*e7gr7x&MRJX>i_}q{drm<-K|$dI4{q4`mWq^pOSJ>u-Wc$j(z1?} z^#i=DkfIA@L${tAvRls$^CxDq+0ongx;EkWJqLPyz4%r2Ry6WwcJ!#g@rG)~iFAj2 zyli8`za_1z7s;S6a)WW*q;N7*Mz|5wTtqT%+G3bceOAc&UD+|0s#%EC1M8@J@Di-d z&6%#$2Fl|+@6?zg6-fg&z~%@UM>OwFy^L(!B@6II&W`4iXqAI0oHRQ`BnBc90}+XV zh{QldVvrzG-D$)*VT#1grCi+Jyqg?eQh2wuAtsAVUSNpyK!UfsC5cn)U2H1csMYHD oPWInE|BxUEf*=TjAPAXx1^^0f-N*jT?f?J)07*qoM6N<$f@g(^$N&HU literal 0 HcmV?d00001 diff --git a/frontend/assets/images/topic.png b/frontend/assets/images/topic.png new file mode 100644 index 0000000000000000000000000000000000000000..f35cd16443fd1dca4fb20c4dcd6ef61fce4ddf61 GIT binary patch literal 477 zcmV<30V4j1P);lyo;Wrmbc8Gb^tY5lWji7!#MsLF zBrD;enD?8!_Zx^9hGCdnM%aRRo<9m9HW&*WrgZLPLhSKTS5>toPb7LkB`>A?K{8J` zyeBsvFjiTXQPVWvJ%ka$TBtA2vAD2jLTfV9M(X&StUFlqo7?I}EVUDv(Ub^WWK zkQ4_iRhOzh^%JoOP^3wcZ1iAE0;uo%g&vDa09m?YYyu2ez}(!CBPgUTMvk6*pb0td zzeY&J=Sy@12}$0IYGL zHTFyt0^CODhJD~%#`gIky!pV`K0kzSAGq{c+rXO-jP3J7un)`)3z!>209xHOcbk)A z2ta}EDNwMupL)y?(6;Sspm*V5GeSea(J`0!x}z{qiGShM;?nkNkzp8yxo!Rc+UA8Q TXmNA(00000NkvXXu0mjf=I6%` literal 0 HcmV?d00001 diff --git a/frontend/eas.json b/frontend/eas.json index 3a90671..0ad80b5 100644 --- a/frontend/eas.json +++ b/frontend/eas.json @@ -1,18 +1,18 @@ -{ - "cli": { - "version": ">= 11.0.3" - }, - "build": { - "development": { - "developmentClient": true, - "distribution": "internal" - }, - "preview": { - "distribution": "internal" - }, - "production": {} - }, - "submit": { - "production": {} - } -} +{ + "cli": { + "version": ">= 11.0.3" + }, + "build": { + "development": { + "developmentClient": true, + "distribution": "internal" + }, + "preview": { + "distribution": "internal" + }, + "production": {} + }, + "submit": { + "production": {} + } +} diff --git a/frontend/eslint.config.mjs b/frontend/eslint.config.mjs index 4bcde3e..89c88d9 100644 --- a/frontend/eslint.config.mjs +++ b/frontend/eslint.config.mjs @@ -1,61 +1,61 @@ -import globals from 'globals'; -import jsEslint from '@eslint/js'; -import typescriptEslint from 'typescript-eslint'; -import eslintPluginReact from 'eslint-plugin-react'; -import eslintConfigPrettier from 'eslint-config-prettier'; - -export default [ - { files: ['**/*.{js,mjs,cjs,ts,jsx,tsx}'] }, - { - settings: { - react: { - version: 'detect', - }, - }, - }, - { - ignores: [ - '.eslintrc.js', - '.prettierrc.json', - 'babel.config.js', - '**/node_modules/', - '.git/', - 'tailwind.config.js', - ], - }, - { - languageOptions: { - globals: { ...globals.browser, ...globals.node }, - }, - }, - jsEslint.configs.recommended, - ...typescriptEslint.configs.recommended, - eslintPluginReact.configs.flat.recommended, - eslintConfigPrettier, - { - rules: { - 'no-duplicate-imports': 'error', - 'no-self-compare': 'error', - 'no-unmodified-loop-condition': 'error', - 'no-unreachable-loop': 'error', - 'no-use-before-define': 'error', - 'no-useless-assignment': 'error', - camelcase: 'error', - 'class-methods-use-this': 'error', - curly: 'error', - 'default-case': 'error', - 'default-case-last': 'error', - eqeqeq: 'error', - 'no-else-return': 'error', - 'no-unneeded-ternary': 'error', - 'no-var': 'error', - 'prefer-const': 'error', - 'prefer-exponentiation-operator': 'warn', - 'require-await': 'error', - 'react/prop-types': 'off', - '@typescript-eslint/no-require-imports': 'off', - semi: 'error', - 'no-extra-semi': 'error', - }, - }, -]; +import globals from 'globals'; +import jsEslint from '@eslint/js'; +import typescriptEslint from 'typescript-eslint'; +import eslintPluginReact from 'eslint-plugin-react'; +import eslintConfigPrettier from 'eslint-config-prettier'; + +export default [ + { files: ['**/*.{js,mjs,cjs,ts,jsx,tsx}'] }, + { + settings: { + react: { + version: 'detect', + }, + }, + }, + { + ignores: [ + '.eslintrc.js', + '.prettierrc.json', + 'babel.config.js', + '**/node_modules/', + '.git/', + 'tailwind.config.js', + ], + }, + { + languageOptions: { + globals: { ...globals.browser, ...globals.node }, + }, + }, + jsEslint.configs.recommended, + ...typescriptEslint.configs.recommended, + eslintPluginReact.configs.flat.recommended, + eslintConfigPrettier, + { + rules: { + 'no-duplicate-imports': 'error', + 'no-self-compare': 'error', + 'no-unmodified-loop-condition': 'error', + 'no-unreachable-loop': 'error', + 'no-use-before-define': 'error', + 'no-useless-assignment': 'error', + camelcase: 'error', + 'class-methods-use-this': 'error', + curly: 'error', + 'default-case': 'error', + 'default-case-last': 'error', + eqeqeq: 'error', + 'no-else-return': 'error', + 'no-unneeded-ternary': 'error', + 'no-var': 'error', + 'prefer-const': 'error', + 'prefer-exponentiation-operator': 'warn', + 'require-await': 'error', + 'react/prop-types': 'off', + '@typescript-eslint/no-require-imports': 'off', + semi: 'error', + 'no-extra-semi': 'error', + }, + }, +]; diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 07f4de7..f23bffb 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@expo/ngrok": "^4.1.0", "@expo/vector-icons": "^14.0.2", + "@gorhom/bottom-sheet": "^5.0.6", "@likashefqet/react-native-image-zoom": "^4.2.0", "@react-native-async-storage/async-storage": "1.23.1", "@react-navigation/bottom-tabs": "^6.6.1", @@ -2458,9 +2459,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.15.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.15.0.tgz", - "integrity": "sha512-tMTqrY+EzbXmKJR5ToI8lxu7jaN5EdmrBFJpQk5JmSlyLsx6o4t27r883K5xsLuCYCpfKBCGswMSWXsM+jB7lg==", + "version": "9.16.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.16.0.tgz", + "integrity": "sha512-tw2HxzQkrbeuvyj1tG2Yqq+0H9wGoI2IMk4EOsQeX+vmd75FtJAzf+gTA69WF+baUKRYQ3x2kbLE08js5OsTVg==", "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3333,6 +3334,45 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/@gorhom/bottom-sheet": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@gorhom/bottom-sheet/-/bottom-sheet-5.0.6.tgz", + "integrity": "sha512-SI/AhPvgRfnCWN6/+wbE6TXwRE4X8F2fLyE4L/0bRwgE34Zenq585qLT139uEcfCIyovC2swC3ICqQpkmWEcFA==", + "license": "MIT", + "dependencies": { + "@gorhom/portal": "1.0.14", + "invariant": "^2.2.4" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-native": "*", + "react": "*", + "react-native": "*", + "react-native-gesture-handler": ">=2.16.1", + "react-native-reanimated": ">=3.16.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-native": { + "optional": true + } + } + }, + "node_modules/@gorhom/portal": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/@gorhom/portal/-/portal-1.0.14.tgz", + "integrity": "sha512-MXyL4xvCjmgaORr/rtryDNFy3kU4qUbKlwtQqqsygd0xX3mhKjOLn6mQK8wfu0RkoE0pBE0nAasRoHua+/QZ7A==", + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.1" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -4644,15 +4684,15 @@ } }, "node_modules/@supabase/realtime-js": { - "version": "2.10.7", - "resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.10.7.tgz", - "integrity": "sha512-OLI0hiSAqQSqRpGMTUwoIWo51eUivSYlaNBgxsXZE7PSoWh12wPRdVt0psUMaUzEonSB85K21wGc7W5jHnT6uA==", + "version": "2.10.9", + "resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.10.9.tgz", + "integrity": "sha512-0AjN65VDNIScZzrrPaVvlND4vbgVS+j9Wcy3zf7e+l9JY4IwCTahFenPLcKy9bkr7KY0wfB7MkipZPKxMaDnjw==", "license": "MIT", "dependencies": { "@supabase/node-fetch": "^2.6.14", "@types/phoenix": "^1.5.4", "@types/ws": "^8.5.10", - "ws": "^8.14.2" + "ws": "^8.18.0" } }, "node_modules/@supabase/realtime-js/node_modules/ws": { @@ -4686,16 +4726,16 @@ } }, "node_modules/@supabase/supabase-js": { - "version": "2.46.1", - "resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.46.1.tgz", - "integrity": "sha512-HiBpd8stf7M6+tlr+/82L8b2QmCjAD8ex9YdSAKU+whB/SHXXJdus1dGlqiH9Umy9ePUuxaYmVkGd9BcvBnNvg==", + "version": "2.46.2", + "resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.46.2.tgz", + "integrity": "sha512-5FEzYMZhfIZrMWEqo5/dQincvrhM+DeMWH3/okeZrkBBW1AJxblOQhnhF4/dfNYK25oZ1O8dAnnxZ9gQqdr40w==", "license": "MIT", "dependencies": { "@supabase/auth-js": "2.65.1", "@supabase/functions-js": "2.4.3", "@supabase/node-fetch": "2.6.15", "@supabase/postgrest-js": "1.16.3", - "@supabase/realtime-js": "2.10.7", + "@supabase/realtime-js": "2.10.9", "@supabase/storage-js": "2.7.1" } }, @@ -4712,9 +4752,9 @@ } }, "node_modules/@tanstack/query-core": { - "version": "5.60.6", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.60.6.tgz", - "integrity": "sha512-tI+k0KyCo1EBJ54vxK1kY24LWj673ujTydCZmzEZKAew4NqZzTaVQJEuaG1qKj2M03kUHN46rchLRd+TxVq/zQ==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.62.0.tgz", + "integrity": "sha512-sx38bGrqF9bop92AXOvzDr0L9fWDas5zXdPglxa9cuqeVSWS7lY6OnVyl/oodfXjgOGRk79IfCpgVmxrbHuFHg==", "license": "MIT", "funding": { "type": "github", @@ -4722,12 +4762,12 @@ } }, "node_modules/@tanstack/react-query": { - "version": "5.61.3", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.61.3.tgz", - "integrity": "sha512-c3Oz9KaCBapGkRewu7AJLhxE9BVqpMcHsd3KtFxSd7FSCu2qGwqfIN37zbSGoyk6Ix9LGZBNHQDPI6GpWABnmA==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.62.0.tgz", + "integrity": "sha512-tj2ltjAn2a3fs+Dqonlvs6GyLQ/LKVJE2DVSYW+8pJ3P6/VCVGrfqv5UEchmlP7tLOvvtZcOuSyI2ooVlR5Yqw==", "license": "MIT", "dependencies": { - "@tanstack/query-core": "5.60.6" + "@tanstack/query-core": "5.62.0" }, "funding": { "type": "github", @@ -4793,9 +4833,9 @@ "license": "MIT" }, "node_modules/@testing-library/react-native": { - "version": "12.8.1", - "resolved": "https://registry.npmjs.org/@testing-library/react-native/-/react-native-12.8.1.tgz", - "integrity": "sha512-/7PIFCpeqAD3j7nzKQhZtm1T6RR/O/tB1We7JHtYP5RpTBj8rPitEpt6xGrD8R0ymOh+DxDKK7Zovfv5uDSRWg==", + "version": "12.9.0", + "resolved": "https://registry.npmjs.org/@testing-library/react-native/-/react-native-12.9.0.tgz", + "integrity": "sha512-wIn/lB1FjV2N4Q7i9PWVRck3Ehwq5pkhAef5X5/bmQ78J/NoOsGbVY2/DG5Y9Lxw+RfE+GvSEh/fe5Tz6sKSvw==", "dev": true, "license": "MIT", "dependencies": { @@ -5005,12 +5045,12 @@ } }, "node_modules/@types/node": { - "version": "22.9.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.3.tgz", - "integrity": "sha512-F3u1fs/fce3FFk+DAxbxc78DF8x0cY09RRL8GnXLmkJ1jvx3TtPdWoTT5/NiYfI5ASqXBmfqJi9dZ3gxMx4lzw==", + "version": "22.10.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.1.tgz", + "integrity": "sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==", "license": "MIT", "dependencies": { - "undici-types": "~6.19.8" + "undici-types": "~6.20.0" } }, "node_modules/@types/node-forge": { @@ -5023,9 +5063,9 @@ } }, "node_modules/@types/phoenix": { - "version": "1.6.5", - "resolved": "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.6.5.tgz", - "integrity": "sha512-xegpDuR+z0UqG9fwHqNoy3rI7JDlvaPh2TY47Fl80oq6g+hXT+c/LEuE43X48clZ6lOfANl5WrPur9fYO1RJ/w==", + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.6.6.tgz", + "integrity": "sha512-PIzZZlEppgrpoT2QgbnDU+MMzuR6BbCjllj0bM70lWoejMeNJAxCchxnv7J3XFkI8MpygtRpzXrIlmWUBclP5A==", "license": "MIT" }, "node_modules/@types/prop-types": { @@ -5061,7 +5101,7 @@ "resolved": "https://registry.npmjs.org/@types/react-native/-/react-native-0.73.0.tgz", "integrity": "sha512-6ZRPQrYM72qYKGWidEttRe6M5DZBEV5F+MHMHqd4TTYx0tfkcdrUFGdef6CCxY0jXU7wldvd/zA/b0A/kTeJmA==", "deprecated": "This is a stub types definition. react-native provides its own type definitions, so you do not need this installed.", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "react-native": "*" @@ -5078,7 +5118,7 @@ "version": "0.76.3", "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.76.3.tgz", "integrity": "sha512-7Fnc3lzCFFpnoyL1egua6d/qUp0KiIpeSLbfOMln4nI2g2BMzyFHdPjJnpLV2NehmS0omOOkrfRqK5u1F/MXzA==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=18" @@ -5088,7 +5128,7 @@ "version": "0.76.3", "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.76.3.tgz", "integrity": "sha512-oJCH/jbYeGmFJql8/y76gqWCCd74pyug41yzYAjREso1Z7xL88JhDyKMvxEnfhSdMOZYVl479N80xFiXPy3ZYA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.25.3", @@ -5111,7 +5151,7 @@ "version": "0.76.3", "resolved": "https://registry.npmjs.org/@react-native/community-cli-plugin/-/community-cli-plugin-0.76.3.tgz", "integrity": "sha512-vgsLixHS24jR0d0QqPykBWFaC+V8x9cM3cs4oYXw3W199jgBNGP9MWcUJLazD2vzrT/lUTVBVg0rBeB+4XR6fg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@react-native/dev-middleware": "0.76.3", @@ -5142,7 +5182,7 @@ "version": "0.76.3", "resolved": "https://registry.npmjs.org/@react-native/gradle-plugin/-/gradle-plugin-0.76.3.tgz", "integrity": "sha512-t0aYZ8ND7+yc+yIm6Yp52bInneYpki6RSIFZ9/LMUzgMKvEB62ptt/7sfho9QkKHCNxE1DJSWIqLIGi/iHHkyg==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=18" @@ -5152,7 +5192,7 @@ "version": "0.76.3", "resolved": "https://registry.npmjs.org/@react-native/js-polyfills/-/js-polyfills-0.76.3.tgz", "integrity": "sha512-pubJFArMMrdZiytH+W95KngcSQs+LsxOBsVHkwgMnpBfRUxXPMK4fudtBwWvhnwN76Oe+WhxSq7vOS5XgoPhmw==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=18" @@ -5162,7 +5202,7 @@ "version": "0.76.3", "resolved": "https://registry.npmjs.org/@react-native/metro-babel-transformer/-/metro-babel-transformer-0.76.3.tgz", "integrity": "sha512-b2zQPXmW7avw/7zewc9nzMULPIAjsTwN03hskhxHUJH5pzUf7pIklB3FrgYPZrRhJgzHiNl3tOPu7vqiKzBYPg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/core": "^7.25.2", @@ -5181,7 +5221,7 @@ "version": "0.76.3", "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.76.3.tgz", "integrity": "sha512-wTGv9pVh3vAOWb29xFm+J9VRe9dUcUcb9FyaMLT/Hxa88W4wqa5ZMe1V9UvrrBiA1G5DKjv8/1ZcDsJhyugVKA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "invariant": "^2.2.4", @@ -5205,7 +5245,7 @@ "version": "0.76.3", "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.76.3.tgz", "integrity": "sha512-0TUhgmlouRNf6yuDIIAdbQl0g1VsONgCMsLs7Et64hjj5VLMCA7np+4dMrZvGZ3wRNqzgeyT9oWJsUm49AcwSQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jest/create-cache-key-function": "^29.6.3", @@ -5267,7 +5307,7 @@ "version": "0.24.0-canary-efb381bbf-20230505", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.24.0-canary-efb381bbf-20230505.tgz", "integrity": "sha512-ABvovCDe/k9IluqSh4/ISoq8tIJnW8euVAWYt5j/bg6dRnqwQwiGO1F/V4AyK96NGF/FB04FhOUDuWj8IKfABA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "loose-envify": "^1.1.0" @@ -5326,17 +5366,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.15.0.tgz", - "integrity": "sha512-+zkm9AR1Ds9uLWN3fkoeXgFppaQ+uEVtfOV62dDmsy9QCNqlRHWNEck4yarvRNrvRcHQLGfqBNui3cimoz8XAg==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.16.0.tgz", + "integrity": "sha512-5YTHKV8MYlyMI6BaEG7crQ9BhSc8RxzshOReKwZwRWN0+XvvTOm+L/UYLCYxFpfwYuAAqhxiq4yae0CMFwbL7Q==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.15.0", - "@typescript-eslint/type-utils": "8.15.0", - "@typescript-eslint/utils": "8.15.0", - "@typescript-eslint/visitor-keys": "8.15.0", + "@typescript-eslint/scope-manager": "8.16.0", + "@typescript-eslint/type-utils": "8.16.0", + "@typescript-eslint/utils": "8.16.0", + "@typescript-eslint/visitor-keys": "8.16.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -5360,16 +5400,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.15.0.tgz", - "integrity": "sha512-7n59qFpghG4uazrF9qtGKBZXn7Oz4sOMm8dwNWDQY96Xlm2oX67eipqcblDj+oY1lLCbf1oltMZFpUso66Kl1A==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.16.0.tgz", + "integrity": "sha512-D7DbgGFtsqIPIFMPJwCad9Gfi/hC0PWErRRHFnaCWoEDYi5tQUDiJCTmGUbBiLzjqAck4KcXt9Ayj0CNlIrF+w==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/scope-manager": "8.15.0", - "@typescript-eslint/types": "8.15.0", - "@typescript-eslint/typescript-estree": "8.15.0", - "@typescript-eslint/visitor-keys": "8.15.0", + "@typescript-eslint/scope-manager": "8.16.0", + "@typescript-eslint/types": "8.16.0", + "@typescript-eslint/typescript-estree": "8.16.0", + "@typescript-eslint/visitor-keys": "8.16.0", "debug": "^4.3.4" }, "engines": { @@ -5389,14 +5429,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.15.0.tgz", - "integrity": "sha512-QRGy8ADi4J7ii95xz4UoiymmmMd/zuy9azCaamnZ3FM8T5fZcex8UfJcjkiEZjJSztKfEBe3dZ5T/5RHAmw2mA==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.16.0.tgz", + "integrity": "sha512-mwsZWubQvBki2t5565uxF0EYvG+FwdFb8bMtDuGQLdCCnGPrDEDvm1gtfynuKlnpzeBRqdFCkMf9jg1fnAK8sg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.15.0", - "@typescript-eslint/visitor-keys": "8.15.0" + "@typescript-eslint/types": "8.16.0", + "@typescript-eslint/visitor-keys": "8.16.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -5407,14 +5447,14 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.15.0.tgz", - "integrity": "sha512-UU6uwXDoI3JGSXmcdnP5d8Fffa2KayOhUUqr/AiBnG1Gl7+7ut/oyagVeSkh7bxQ0zSXV9ptRh/4N15nkCqnpw==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.16.0.tgz", + "integrity": "sha512-IqZHGG+g1XCWX9NyqnI/0CX5LL8/18awQqmkZSl2ynn8F76j579dByc0jhfVSnSnhf7zv76mKBQv9HQFKvDCgg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.15.0", - "@typescript-eslint/utils": "8.15.0", + "@typescript-eslint/typescript-estree": "8.16.0", + "@typescript-eslint/utils": "8.16.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -5435,9 +5475,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.15.0.tgz", - "integrity": "sha512-n3Gt8Y/KyJNe0S3yDCD2RVKrHBC4gTUcLTebVBXacPy091E6tNspFLKRXlk3hwT4G55nfr1n2AdFqi/XMxzmPQ==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.16.0.tgz", + "integrity": "sha512-NzrHj6thBAOSE4d9bsuRNMvk+BvaQvmY4dDglgkgGC0EW/tB3Kelnp3tAKH87GEwzoxgeQn9fNGRyFJM/xd+GQ==", "dev": true, "license": "MIT", "engines": { @@ -5449,14 +5489,14 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.15.0.tgz", - "integrity": "sha512-1eMp2JgNec/niZsR7ioFBlsh/Fk0oJbhaqO0jRyQBMgkz7RrFfkqF9lYYmBoGBaSiLnu8TAPQTwoTUiSTUW9dg==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.16.0.tgz", + "integrity": "sha512-E2+9IzzXMc1iaBy9zmo+UYvluE3TW7bCGWSF41hVWUE01o8nzr1rvOQYSxelxr6StUvRcTMe633eY8mXASMaNw==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "8.15.0", - "@typescript-eslint/visitor-keys": "8.15.0", + "@typescript-eslint/types": "8.16.0", + "@typescript-eslint/visitor-keys": "8.16.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -5494,16 +5534,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.15.0.tgz", - "integrity": "sha512-k82RI9yGhr0QM3Dnq+egEpz9qB6Un+WLYhmoNcvl8ltMEededhh7otBVVIDDsEEttauwdY/hQoSsOv13lxrFzQ==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.16.0.tgz", + "integrity": "sha512-C1zRy/mOL8Pj157GiX4kaw7iyRLKfJXBR3L82hk5kS/GyHcOFmy4YUq/zfZti72I9wnuQtA/+xzft4wCC8PJdA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.15.0", - "@typescript-eslint/types": "8.15.0", - "@typescript-eslint/typescript-estree": "8.15.0" + "@typescript-eslint/scope-manager": "8.16.0", + "@typescript-eslint/types": "8.16.0", + "@typescript-eslint/typescript-estree": "8.16.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -5522,13 +5562,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.15.0.tgz", - "integrity": "sha512-h8vYOulWec9LhpwfAdZf2bjr8xIp0KNKnpgqSz0qqYYKAW/QZKw3ktRndbiAtUz4acH4QLQavwZBYCc0wulA/Q==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.16.0.tgz", + "integrity": "sha512-pq19gbaMOmFE3CbL0ZB8J8BFCo2ckfHBfaIsaOZgBIF4EoISJIdLX5xRhd0FGB0LlHReNRuzoJoMGpTjq8F2CQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.15.0", + "@typescript-eslint/types": "8.16.0", "eslint-visitor-keys": "^4.2.0" }, "engines": { @@ -6209,9 +6249,9 @@ } }, "node_modules/axios": { - "version": "1.7.7", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", - "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.8.tgz", + "integrity": "sha512-Uu0wb7KNqK2t5K+YQyVCLM76prD5sRFjKHbJYCP1J7JFGEQ6nN7HWn9+04LAeiJ3ji54lgS/gZCH1oxyrf1SPw==", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", @@ -6857,9 +6897,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001684", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001684.tgz", - "integrity": "sha512-G1LRwLIQjBQoyq0ZJGqGIJUXzJ8irpbjHLpVRXDvBEScFJ9b17sgK6vlx0GAJFE21okD7zXl08rRRUfq6HdoEQ==", + "version": "1.0.30001685", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001685.tgz", + "integrity": "sha512-e/kJN1EMyHQzgcMEEgoo+YTCO1NGCmIYHk5Qk8jT6AazWemS5QFKJ5ShCJlH3GZrNIdZofcNCEwZqbMjjKzmnA==", "funding": [ { "type": "opencollective", @@ -7020,15 +7060,15 @@ "license": "MIT" }, "node_modules/class-variance-authority": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.0.tgz", - "integrity": "sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", + "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==", "license": "Apache-2.0", "dependencies": { - "clsx": "2.0.0" + "clsx": "^2.1.1" }, "funding": { - "url": "https://joebell.co.uk" + "url": "https://polar.sh/cva" } }, "node_modules/clean-stack": { @@ -7123,9 +7163,9 @@ } }, "node_modules/clsx": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", - "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", "license": "MIT", "engines": { "node": ">=6" @@ -8118,9 +8158,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.64", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.64.tgz", - "integrity": "sha512-IXEuxU+5ClW2IGEYFC2T7szbyVgehupCWQe5GNh+H065CD6U6IFN0s4KeAMFGNmQolRU4IV7zGBWSYMmZ8uuqQ==", + "version": "1.5.67", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.67.tgz", + "integrity": "sha512-nz88NNBsD7kQSAGGJyp8hS6xSPtWwqNogA0mjtc2nUYeEf3nURK9qpV18TuBdDmEDgVWotS8Wkzf+V52dSQ/LQ==", "license": "ISC" }, "node_modules/emittery": { @@ -8384,15 +8424,15 @@ } }, "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", "dev": true, "license": "MIT", "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" }, "engines": { "node": ">= 0.4" @@ -8451,9 +8491,9 @@ } }, "node_modules/eslint": { - "version": "9.15.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.15.0.tgz", - "integrity": "sha512-7CrWySmIibCgT1Os28lUU6upBshZ+GxybLOrmRzi08kS8MBuO8QA7pXEgYgY5W8vK3e74xv0lpjo9DbaGU9Rkw==", + "version": "9.16.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.16.0.tgz", + "integrity": "sha512-whp8mSQI4C8VXd+fLgSM0lh3UlmcFtVwUQjyKCFfsp+2ItAIYhlq/hqGahGqHE6cv9unM41VlqKk2VtKYR2TaA==", "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", @@ -8461,7 +8501,7 @@ "@eslint/config-array": "^0.19.0", "@eslint/core": "^0.9.0", "@eslint/eslintrc": "^3.2.0", - "@eslint/js": "9.15.0", + "@eslint/js": "9.16.0", "@eslint/plugin-kit": "^0.2.3", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", @@ -9302,9 +9342,9 @@ "license": "MIT" }, "node_modules/flow-parser": { - "version": "0.254.2", - "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.254.2.tgz", - "integrity": "sha512-18xCQaVdKNCY0TAEhwUdk1HmRdgsPSraWwu0Zifqo5M4Ubi9LjWTAdlfBFb07Os+fQ9TmzxlyZN6OxK0m9xrBw==", + "version": "0.255.0", + "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.255.0.tgz", + "integrity": "sha512-7QHV2m2mIMh6yIMaAPOVbyNEW77IARwO69d4DgvfDCjuORiykdMLf7XBjF7Zeov7Cpe1OXJ8sB6/aaCE3xuRBw==", "license": "MIT", "engines": { "node": ">=0.4.0" @@ -9625,9 +9665,9 @@ "peer": true }, "node_modules/globals": { - "version": "15.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-15.12.0.tgz", - "integrity": "sha512-1+gLErljJFhbOVyaetcwJiJ4+eLe45S2E7P5UiZ9xGfeq3ATQf5DOv9G7MH3gGbKQLkzmNh2DxfZwLdw+j6oTQ==", + "version": "15.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.13.0.tgz", + "integrity": "sha512-49TewVEz0UxZjr1WYYsWpPrhyC/B/pA8Bq0fUmet2n+eR7yn0IvNzNaoBwnK6mdkzcN+se7Ez9zUgULTz2QH4g==", "dev": true, "license": "MIT", "engines": { @@ -9675,13 +9715,16 @@ } }, "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.1.0.tgz", + "integrity": "sha512-FQoVQnqcdk4hVM4JN1eromaun4iuS34oStkdlLENLdpULsuQcTyXj8w7ayhuUfPwEYZ1ZOooOTT6fdA9Vmx/RA==", "dev": true, "license": "MIT", "dependencies": { - "get-intrinsic": "^1.1.3" + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -9758,11 +9801,14 @@ } }, "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.1.0.tgz", + "integrity": "sha512-QLdzI9IIO1Jg7f9GT1gXpPpXArAn6cS31R1eEZqz08Gc+uQ8/XiqHWt17Fiw+2p6oTTIq5GXEpQkAlA88YRl/Q==", "dev": true, "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7" + }, "engines": { "node": ">= 0.4" }, @@ -10206,14 +10252,14 @@ } }, "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.0.tgz", + "integrity": "sha512-kR5g0+dXf/+kXnqI+lu0URKYPKgICtHGGNCDSB10AaUFj3o/HkB3u7WfpRBJGFopxxY0oH3ux7ZsDjLtK7xqvw==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "call-bind": "^1.0.7", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -10419,13 +10465,14 @@ } }, "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.0.tgz", + "integrity": "sha512-KVSZV0Dunv9DTPkhXwcZ3Q+tUc9TsaE1ZwX5J2WMvsSGS6Md8TFPun5uwh0yRdrNerI6vf/tbJxqSx4c1ZI1Lw==", "dev": true, "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bind": "^1.0.7", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -10481,14 +10528,16 @@ "license": "MIT" }, "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.0.tgz", + "integrity": "sha512-B6ohK4ZmoftlUe+uvenXSbPJFo6U37BH7oO1B3nQH8f/7h27N56s85MhUtbFJAziz5dcmuR3i8ovUl35zp8pFA==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "call-bind": "^1.0.7", + "gopd": "^1.1.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -10539,13 +10588,14 @@ } }, "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.0.tgz", + "integrity": "sha512-PlfzajuF9vSo5wErv3MJAKD/nqf9ngAs1NFQYm16nUYFO2IzxJ2hcm+IOCg+EEopdykNNUhVq5cz35cAUxU8+g==", "dev": true, "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bind": "^1.0.7", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -12866,9 +12916,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", "funding": [ { "type": "github", @@ -13136,9 +13186,9 @@ } }, "node_modules/nwsapi": { - "version": "2.2.13", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.13.tgz", - "integrity": "sha512-cTGB9ptp9dY9A5VbMSe7fQBcl/tt22Vcqdq8+eN93rblOuE0aCFu4aZ2vMwct/2t+lFnosm8RkQW1I0Omb1UtQ==", + "version": "2.2.16", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.16.tgz", + "integrity": "sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ==", "dev": true, "license": "MIT" }, @@ -14172,13 +14222,16 @@ "license": "MIT" }, "node_modules/psl": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.13.0.tgz", - "integrity": "sha512-BFwmFXiJoFqlUpZ5Qssolv15DMyc84gTBds1BjsV1BfXEo1UyyD7GsmN67n7J77uRhoSNW1AXtXKPLcBFQn9Aw==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", + "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", "dev": true, "license": "MIT", "dependencies": { "punycode": "^2.3.1" + }, + "funding": { + "url": "https://github.com/sponsors/lupomontero" } }, "node_modules/pump": { @@ -14573,9 +14626,9 @@ } }, "node_modules/react-native-reanimated": { - "version": "3.16.2", - "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.16.2.tgz", - "integrity": "sha512-Jk8y+iOLcK3J8YK3Qj/U+zclwfetgM1fFhlYaxFrJ5TPvuwdRG5YY1pvO91FcZ3C1+0meGHR6BZGl9d/Z0xh3Q==", + "version": "3.16.3", + "resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.16.3.tgz", + "integrity": "sha512-OWlA6e1oHhytTpc7WiSZ7Tmb8OYwLKYZz29Sz6d6WAg60Hm5GuAiKIWUG7Ako7FLcYhFkA0pEQ2xPMEYUo9vlw==", "license": "MIT", "dependencies": { "@babel/plugin-transform-arrow-functions": "^7.0.0-0", @@ -15423,10 +15476,13 @@ } }, "node_modules/shell-quote": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", - "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz", + "integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==", "license": "MIT", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -16488,9 +16544,9 @@ } }, "node_modules/ts-api-utils": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.1.tgz", - "integrity": "sha512-5RU2/lxTA3YUZxju61HO2U6EoZLvBLtmV2mbTvqyu4a/7s7RmJPT+1YekhMVsQhznRWk/czIwDUg+V8Q9ZuG4w==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", + "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", "dev": true, "license": "MIT", "engines": { @@ -16685,15 +16741,15 @@ } }, "node_modules/typescript-eslint": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.15.0.tgz", - "integrity": "sha512-wY4FRGl0ZI+ZU4Jo/yjdBu0lVTSML58pu6PgGtJmCufvzfV565pUF6iACQt092uFOd49iLOTX/sEVmHtbSrS+w==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.16.0.tgz", + "integrity": "sha512-wDkVmlY6O2do4V+lZd0GtRfbtXbeD0q9WygwXXSJnC1xorE8eqyC2L1tJimqpSeFrOzRlYtWnUp/uzgHQOgfBQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.15.0", - "@typescript-eslint/parser": "8.15.0", - "@typescript-eslint/utils": "8.15.0" + "@typescript-eslint/eslint-plugin": "8.16.0", + "@typescript-eslint/parser": "8.16.0", + "@typescript-eslint/utils": "8.16.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -16763,9 +16819,9 @@ } }, "node_modules/undici-types": { - "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", "license": "MIT" }, "node_modules/unicode-canonical-property-names-ecmascript": { @@ -17298,9 +17354,9 @@ } }, "node_modules/which-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", - "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.16.tgz", + "integrity": "sha512-g+N+GAWiRj66DngFwHvISJd+ITsyphZvD1vChfVg6cEdnzy53GzB3oy0fUNlvhz7H7+MiqhYr26qxQShCpKTTQ==", "dev": true, "license": "MIT", "dependencies": { diff --git a/frontend/package.json b/frontend/package.json index a7da7dc..eedf5fc 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -15,6 +15,7 @@ "dependencies": { "@expo/ngrok": "^4.1.0", "@expo/vector-icons": "^14.0.2", + "@gorhom/bottom-sheet": "^5.0.6", "@likashefqet/react-native-image-zoom": "^4.2.0", "@react-native-async-storage/async-storage": "1.23.1", "@react-navigation/bottom-tabs": "^6.6.1", diff --git a/frontend/src/components/Button.tsx b/frontend/src/components/Button.tsx index 3f6e390..dbf95f3 100644 --- a/frontend/src/components/Button.tsx +++ b/frontend/src/components/Button.tsx @@ -40,7 +40,7 @@ const backgroundStyles = cva( state: 'default', size: 'medium', }, - } + }, ); // Text styles @@ -74,13 +74,12 @@ const textStyles = cva( state: 'default', size: 'medium', }, - } + }, ); - // Define button props interface ButtonProps extends TouchableOpacityProps { - children: React.ReactNode; + children: React.ReactNode; icon?: React.ReactNode; type?: 'primary' | 'secondary' | 'plain-dark'; state?: 'default' | 'pressed' | 'disabled'; @@ -113,11 +112,9 @@ const Button: React.FC = ({ {...props} > {icon && icon} - - {children} - + {children} ); }; -export default Button; \ No newline at end of file +export default Button; diff --git a/frontend/src/components/Card.tsx b/frontend/src/components/Card.tsx index 3f7ed8b..5a9b35f 100644 --- a/frontend/src/components/Card.tsx +++ b/frontend/src/components/Card.tsx @@ -7,23 +7,16 @@ const StyledView = styled(View); const cardVariants = cva('bg-white rounded-[16px] border border-border p-4', { variants: {}, - defaultVariants: {} + defaultVariants: {}, }); interface CardProps extends ViewProps, VariantProps { children: React.ReactNode; } -export function Card({ - children, - className, - ...props -}: CardProps & { className?: string }) { +export function Card({ children, className, ...props }: CardProps & { className?: string }) { return ( - + {children} ); diff --git a/frontend/src/components/ProgressBar.tsx b/frontend/src/components/ProgressBar.tsx index 9f78032..2854594 100644 --- a/frontend/src/components/ProgressBar.tsx +++ b/frontend/src/components/ProgressBar.tsx @@ -2,7 +2,10 @@ import React from 'react'; import { View } from 'react-native'; import { styled } from 'nativewind'; -const ProgressBarContainer = styled(View, 'w-full h-2 bg-gray-200 rounded-full overflow-hidden mb-2'); +const ProgressBarContainer = styled( + View, + 'w-full h-2 bg-gray-200 rounded-full overflow-hidden mb-2', +); const ProgressBarFill = styled(View, 'h-full bg-defaultPrimary rounded-full'); const ProgressBar = ({ current, total }) => { diff --git a/frontend/src/components/SearchBar.tsx b/frontend/src/components/SearchBar.tsx index 8c0cc2f..50ad4a2 100644 --- a/frontend/src/components/SearchBar.tsx +++ b/frontend/src/components/SearchBar.tsx @@ -1,70 +1,80 @@ -import React from 'react'; -import { View, Pressable, Image, TextInput, Dimensions, GestureResponderEvent } from 'react-native'; -import { styled } from 'nativewind'; -import { cva, type VariantProps } from 'class-variance-authority'; - -const StyledView = styled(View); -const StyledPressable = styled(Pressable); -const StyledImage = styled(Image); -const StyledTextInput = styled(TextInput); - -const searchBarVariants = cva('flex-row items-center px-4 py-2 rounded-full', { - variants: { - intent: { - selected: 'border border-borderSelected bg-surfaceFG text-defaultText', - unselected: 'border border-borderPrimary bg-surfaceFG text-placeholderText', - disabled: 'border border-borderPrimary bg-surfaceDisabled text-placeholderText', - }, - icon: { - 'x-default': '../../assets/images/x-icon-default.png', - 'search-default': '../../assets/images/search-icon-default.png', - 'x-disabled': '../../assets/images/x-icon-disabled.png', - 'search-disabled': '../../assets/images/search-icon-disabled.png', - }, - }, - compoundVariants: [ - { intent: 'selected', icon: 'x-default', className: 'bg-surfaceFG' }, - { intent: 'unselected', icon: 'search-default', className: 'bg-surfaceFG' }, - { intent: 'disabled', icon: 'x-disabled', className: 'bg-surfaceDisabled' }, - { intent: 'disabled', icon: 'search-disabled', className: 'bg-surfaceDisabled' }, - ], -}); - -const iconVariants = { - 'x-default': require('../../assets/images/x-icon-default.png'), - 'x-disabled': require('../../assets/images/x-icon-disabled.png'), - 'search-default': require('../../assets/images/search-icon-default.png'), - 'search-disabled': require('../../assets/images/search-icon-disabled.png') -}; - -const { height: screenHeight } = Dimensions.get('window'); -const calculatedWidth = (239 / 1000) * screenHeight; -const calculatedHeight = (42 / 1000) * screenHeight; - -type SearchBarProps = VariantProps & { - value: string; - onValueChange: (text: string) => void; - onPressed: (event: GestureResponderEvent) => void; - intent: string; - icon: string; - textColor: string; -}; - -const SearchBar: React.FC = ({ value, intent, icon, textColor, onValueChange, onPressed }) => { - return ( - - - - - - - ); -}; - -export default SearchBar; \ No newline at end of file +import React from 'react'; +import { View, Pressable, Image, TextInput, Dimensions, GestureResponderEvent } from 'react-native'; +import { styled } from 'nativewind'; +import { cva, type VariantProps } from 'class-variance-authority'; + +const StyledView = styled(View); +const StyledPressable = styled(Pressable); +const StyledImage = styled(Image); +const StyledTextInput = styled(TextInput); + +const searchBarVariants = cva('flex-row items-center px-4 py-2 rounded-full', { + variants: { + intent: { + selected: 'border border-borderSelected bg-surfaceFG text-defaultText', + unselected: 'border border-borderPrimary bg-surfaceFG text-placeholderText', + disabled: 'border border-borderPrimary bg-surfaceDisabled text-placeholderText', + }, + icon: { + 'x-default': '../../assets/images/x-icon-default.png', + 'search-default': '../../assets/images/search-icon-default.png', + 'x-disabled': '../../assets/images/x-icon-disabled.png', + 'search-disabled': '../../assets/images/search-icon-disabled.png', + }, + }, + compoundVariants: [ + { intent: 'selected', icon: 'x-default', className: 'bg-surfaceFG' }, + { intent: 'unselected', icon: 'search-default', className: 'bg-surfaceFG' }, + { intent: 'disabled', icon: 'x-disabled', className: 'bg-surfaceDisabled' }, + { intent: 'disabled', icon: 'search-disabled', className: 'bg-surfaceDisabled' }, + ], +}); + +const iconVariants = { + 'x-default': require('../../assets/images/x-icon-default.png'), + 'x-disabled': require('../../assets/images/x-icon-disabled.png'), + 'search-default': require('../../assets/images/search-icon-default.png'), + 'search-disabled': require('../../assets/images/search-icon-disabled.png'), +}; + +const { height: screenHeight } = Dimensions.get('window'); +const calculatedWidth = (239 / 1000) * screenHeight; +const calculatedHeight = (42 / 1000) * screenHeight; + +type SearchBarProps = VariantProps & { + value: string; + onValueChange: (text: string) => void; + onPressed: (event: GestureResponderEvent) => void; + intent: string; + icon: string; + textColor: string; +}; + +const SearchBar: React.FC = ({ + value, + intent, + icon, + textColor, + onValueChange, + onPressed, +}) => { + return ( + + + + + + + ); +}; + +export default SearchBar; diff --git a/frontend/src/components/SideBySide.tsx b/frontend/src/components/SideBySide.tsx index 1a14b50..418e0a7 100644 --- a/frontend/src/components/SideBySide.tsx +++ b/frontend/src/components/SideBySide.tsx @@ -7,14 +7,10 @@ const StyledView = styled(View); const SideBySide = ({ leftComponent, rightComponent, spacing = 'mr-2', containerStyle = '' }) => { return ( - - {leftComponent} - - - {rightComponent} - + {leftComponent} + {rightComponent} ); }; -export default SideBySide; \ No newline at end of file +export default SideBySide; diff --git a/frontend/src/components/Tag.tsx b/frontend/src/components/Tag.tsx index 6ff13a7..fb2cf91 100644 --- a/frontend/src/components/Tag.tsx +++ b/frontend/src/components/Tag.tsx @@ -10,18 +10,18 @@ const tagVariants = cva('flex flex-row items-center rounded-lg px-3 py-1', { variants: { level: { neutral: 'bg-gray-900', - success: 'bg-success', + success: 'bg-success', warning: 'bg-[#F7B418]', critical: 'bg-[#D32246]', neutralSubdued: 'bg-gray-200', successSubdued: 'bg-[#ECF3ED]', warningSubdued: 'bg-[#F9EFD7]', - criticalSubdued: 'bg-[#F8EDED]' + criticalSubdued: 'bg-[#F8EDED]', }, }, defaultVariants: { level: 'neutral', - } + }, }); const tagIconVariants = cva('', { @@ -34,10 +34,10 @@ const tagIconVariants = cva('', { neutralSubdued: 'text-gray-600', successSubdued: 'text-success', warningSubdued: 'text-[#F7B418]', - criticalSubdued: 'text-[#D32246]' - } - } -}) + criticalSubdued: 'text-[#D32246]', + }, + }, +}); const tagTextVariants = cva('text-xs font-sourceSans3Medium', { variants: { @@ -49,12 +49,12 @@ const tagTextVariants = cva('text-xs font-sourceSans3Medium', { neutralSubdued: 'text-gray-600', successSubdued: 'text-success', warningSubdued: 'text-[#F7B418]', - criticalSubdued: 'text-[#D32246]' - } + criticalSubdued: 'text-[#D32246]', + }, }, defaultVariants: { level: 'neutral', - } + }, }); interface TagProps extends ViewProps, VariantProps { @@ -70,10 +70,7 @@ export function Tag({ ...props }: TagProps & { className?: string }) { return ( - + {icon} {children} diff --git a/frontend/src/components/TextField.tsx b/frontend/src/components/TextField.tsx index 4de55e3..b7c39cb 100644 --- a/frontend/src/components/TextField.tsx +++ b/frontend/src/components/TextField.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { styled } from 'nativewind'; import { cva, type VariantProps } from 'class-variance-authority'; -import { TextInput, View, Text, TextInputProps, ImageSourcePropType, Image} from 'react-native'; +import { TextInput, View, Text, TextInputProps, ImageSourcePropType, Image } from 'react-native'; const StyledText = styled(Text); const StyledTextInput = styled(TextInput); @@ -9,171 +9,111 @@ const StyledView = styled(View); const StyledImage = styled(Image); const textFieldVariants = cva('textField', { - variants: { - intent: { - default: [ - 'flex w-82', - 'flex-col', - 'items-center', - 'bg-surfaceFG', - 'border-border', - 'border-x-[0.3px]', - 'border-y-[0.3px]', - 'rounded-[12px]', - ], - hover: [ - 'flex w-82', - 'flex-col', - 'items-center', - 'bg-gray-200', - 'border-gray-300', - 'border-x-[0.3px]', - 'border-y-[0.3px]', - 'rounded-[12px]', - ], - focus: [ - 'flex w-82', - 'flex-col', - 'items-center', - 'bg-surfaceFG', - 'border-border-selected', - 'border-x-[0.3px]', - 'border-y-[0.3px]', - 'rounded-[12px]', - ], - error: [ - 'flex w-82', - 'flex-row', - 'items-center', - 'bg-surfaceFG', - 'border-x-[0.3px]', - 'border-y-[0.3px]', - 'rounded-[12px]', - 'border-error', - ], - filled: [ - 'flex w-82', - 'flex-col', - 'items-center', - 'bg-surfaceFG', - 'border-gray-200', - 'border-x-[0.3px]', - 'border-y-[0.3px]', - 'rounded-[12px]', - - ], - disabled: [ - 'flex w-82', - 'flex-col', - 'items-center', - 'bg-gray-300', - 'border-gray-500', - 'border-x-[0.3px]', - 'border-y-[0.3px]', - 'rounded-[12px]', - ] - }, - size: { - medium: [ - 'flex', - 'p-[8px_12px]', - 'items-center', - 'gap-2', - 'self-stretch', - - ], - large: [ - 'flex', - 'p-[12px_16px]', - 'items-center', - 'gap-2', - 'self-stretch', - - ], - }, - icon: { - default: [ - - ], - left: [ - 'flex-row', - 'items-center', - 'pl-4', - ], - right: [ - 'flex-row', - 'items-center', - 'pr-4', - 'justify-between', - ], - prefix: [ - 'flex-row', - 'items-center', - 'pl-4', - ], - suffix: [ - 'flex-row', - 'items-center', - 'pr-4', - 'justify-between', - ], - counter: [ - 'flex-row', - 'justify-between', - 'items-center', - 'pr-4', - ], - } + variants: { + intent: { + default: [ + 'flex w-82', + 'flex-col', + 'items-center', + 'bg-surfaceFG', + 'border-border', + 'border-x-[0.3px]', + 'border-y-[0.3px]', + 'rounded-[12px]', + ], + hover: [ + 'flex w-82', + 'flex-col', + 'items-center', + 'bg-gray-200', + 'border-gray-300', + 'border-x-[0.3px]', + 'border-y-[0.3px]', + 'rounded-[12px]', + ], + focus: [ + 'flex w-82', + 'flex-col', + 'items-center', + 'bg-surfaceFG', + 'border-border-selected', + 'border-x-[0.3px]', + 'border-y-[0.3px]', + 'rounded-[12px]', + ], + error: [ + 'flex w-82', + 'flex-row', + 'items-center', + 'bg-surfaceFG', + 'border-x-[0.3px]', + 'border-y-[0.3px]', + 'rounded-[12px]', + 'border-error', + ], + filled: [ + 'flex w-82', + 'flex-col', + 'items-center', + 'bg-surfaceFG', + 'border-gray-200', + 'border-x-[0.3px]', + 'border-y-[0.3px]', + 'rounded-[12px]', + ], + disabled: [ + 'flex w-82', + 'flex-col', + 'items-center', + 'bg-gray-300', + 'border-gray-500', + 'border-x-[0.3px]', + 'border-y-[0.3px]', + 'rounded-[12px]', + ], + }, + size: { + medium: ['flex', 'p-[8px_12px]', 'items-center', 'gap-2', 'self-stretch'], + large: ['flex', 'p-[12px_16px]', 'items-center', 'gap-2', 'self-stretch'], }, - }); + icon: { + default: [], + left: ['flex-row', 'items-center', 'pl-4'], + right: ['flex-row', 'items-center', 'pr-4', 'justify-between'], + prefix: ['flex-row', 'items-center', 'pl-4'], + suffix: ['flex-row', 'items-center', 'pr-4', 'justify-between'], + counter: ['flex-row', 'justify-between', 'items-center', 'pr-4'], + }, + }, +}); //variants for different text field text styles const textFieldTextVariants = cva('text', { - variants: { - intent: { - default: [ - 'body-regular', - 'color-gray-600', - ], - hover: [ - 'body-regular', - 'color-gray-600', - ], - focus: [ - 'body-regular', - 'color-default-text', - ], - error: [ - 'body-regular', - 'color-default-text', - ], - filled: [ - 'body-regular', - 'color-default-text', - ], - disabled: [ - 'body-regular', - 'color-gray-500', - ] - }, + variants: { + intent: { + default: ['body-regular', 'color-gray-600'], + hover: ['body-regular', 'color-gray-600'], + focus: ['body-regular', 'color-default-text'], + error: ['body-regular', 'color-default-text'], + filled: ['body-regular', 'color-default-text'], + disabled: ['body-regular', 'color-gray-500'], }, - }); + }, +}); - export interface TextFieldProps - extends TextInputProps, - VariantProps { - //route to the icon optional - iconRoute?: ImageSourcePropType; - //placeholder for the text field - placeholder: string; - //error message - errorMessage?: string; - //preffix - prefix?: string; - //suffix - suffix?: string; - //counter value - count?: string; +export interface TextFieldProps extends TextInputProps, VariantProps { + //route to the icon optional + iconRoute?: ImageSourcePropType; + //placeholder for the text field + placeholder: string; + //error message + errorMessage?: string; + //preffix + prefix?: string; + //suffix + suffix?: string; + //counter value + count?: string; } /** @@ -189,48 +129,55 @@ const textFieldTextVariants = cva('text', { * @param count The value you want to counter to be out of (optional) */ -const TextField: React.FC = ({iconRoute, intent, size, icon, errorMessage, placeholder, prefix, suffix, count}) => { - +const TextField: React.FC = ({ + iconRoute, + intent, + size, + icon, + errorMessage, + placeholder, + prefix, + suffix, + count, +}) => { const [value, setValue] = React.useState(''); function onChangeInput(text) { setValue(text); } - + return ( - - - {(icon === 'left') && iconRoute && ( - + + + {icon === 'left' && iconRoute && } + {icon === 'prefix' && prefix && ( + {prefix} )} - {(icon === 'prefix') && prefix && ( - {prefix} + + {icon === 'right' && iconRoute && ( + + )} + {icon === 'suffix' && suffix && ( + {suffix} + )} + {icon === 'counter' && ( + {`${value.length}/${count}`} )} - - {(icon === 'right') && iconRoute && ( - - )} - {(icon === 'suffix') && suffix && ( - {suffix} - )} - {icon === 'counter' && ( - {`${value.length}/${count}`} - )} - {intent === 'error' && errorMessage && ( - + - {errorMessage} - + {errorMessage} + )} - + ); }; -export default TextField; \ No newline at end of file +export default TextField; diff --git a/frontend/src/components/WideButton.tsx b/frontend/src/components/WideButton.tsx new file mode 100644 index 0000000..ef3d841 --- /dev/null +++ b/frontend/src/components/WideButton.tsx @@ -0,0 +1,87 @@ +import React from 'react'; +import { TouchableOpacity, Text, Image, ImageSourcePropType } from 'react-native'; +import { styled } from 'nativewind'; +import { NavigationScreenProp } from 'react-navigation'; +import { cva, type VariantProps } from 'class-variance-authority'; + +const StyledTouchableOpacity = styled(TouchableOpacity); +const StyledText = styled(Text); +const StyledImage = styled(Image); + +//variants for different button styles +const buttonVariants = cva('button', { + variants: { + intent: { + //green button + primary: [ + 'w-full', + 'h-full', + 'bg-defaultPrimary', + 'rounded-full', + 'flex', + 'items-center', + 'justify-center', + 'flex-row', + ], + //outline button + secondary: [ + 'w-full', + 'h-full', + 'border-solid', + 'border-x-[0.3vw]', + 'border-y-[0.3vw]', + 'rounded-full', + 'flex', + 'items-center', + 'justify-center', + 'border-defaultPrimary', + 'flex-row', + ], + }, + }, +}); + +//variants for different button text styles +const buttonTextVariants = cva('text', { + variants: { + intent: { + //green button text + primary: ['text-[2vh]', 'font-sourceSans3', 'text-white', 'px-[1vw]'], + //outline button text + secondary: ['text-[2vh]', 'font-sourceSans3', 'text-defaultPrimary', 'px-[1vw]'], + }, + }, +}); + +export interface ButtonProps + extends React.ButtonHTMLAttributes, + VariantProps { + //name of button + name: string; + //route to button's icon + iconRoute: ImageSourcePropType; + // This actually should be `any`, so disabling the linter rule + // eslint-disable-next-line @typescript-eslint/no-explicit-any + navigation: NavigationScreenProp; +} + +/** + * Wide button component + * @param name name of button. + * @param iconRoute route to button's icon. + * @param intent button variant (primary = green, secondary = outline). + * @param navigation navigation prop to direct to another screen/action + */ +const WideButton: React.FC = ({ name, iconRoute, intent, navigation }) => { + return ( + + {name} + + + ); +}; + +export default WideButton; diff --git a/frontend/src/components/carousel.tsx b/frontend/src/components/carousel.tsx index ffd0975..22add7e 100644 --- a/frontend/src/components/carousel.tsx +++ b/frontend/src/components/carousel.tsx @@ -1,29 +1,29 @@ -import Carousel from 'react-native-reanimated-carousel'; -import React from 'react'; -import { Dimensions, View } from 'react-native'; -import { styled } from 'nativewind'; - -interface GenericCarouselProps { - components: React.ReactNode[]; // ReactNode allows you to pass JSX elements -} -const StyledView = styled(View); - -export default function GenericCarousel({ components }: GenericCarouselProps) { - const width = Dimensions.get('window').width; - - return ( - - ( - - {item} - - )} - scrollAnimationDuration={1000} - /> - - ); -} +import Carousel from 'react-native-reanimated-carousel'; +import React from 'react'; +import { Dimensions, View } from 'react-native'; +import { styled } from 'nativewind'; + +interface GenericCarouselProps { + components: React.ReactNode[]; // ReactNode allows you to pass JSX elements +} +const StyledView = styled(View); + +export default function GenericCarousel({ components }: GenericCarouselProps) { + const width = Dimensions.get('window').width; + + return ( + + ( + + {item} + + )} + scrollAnimationDuration={1000} + /> + + ); +} diff --git a/frontend/src/constants.ts b/frontend/src/constants.ts index 7b7cf57..19dd0f5 100644 --- a/frontend/src/constants.ts +++ b/frontend/src/constants.ts @@ -1,4 +1,4 @@ -export const API_URL = "https://27cf-100-4-222-177.ngrok-free.app"; -export const SUPABASE_URL = "https://a98b-100-4-222-177.ngrok-free.app"; -export const SUPABASE_JWT_SECRET = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0"; - +export const API_URL = 'https://27cf-100-4-222-177.ngrok-free.app'; +export const SUPABASE_URL = 'https://a98b-100-4-222-177.ngrok-free.app'; +export const SUPABASE_JWT_SECRET = + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0'; diff --git a/frontend/src/screens/home/components/BottomSheetComponent.tsx b/frontend/src/screens/home/components/BottomSheetComponent.tsx new file mode 100644 index 0000000..0d47162 --- /dev/null +++ b/frontend/src/screens/home/components/BottomSheetComponent.tsx @@ -0,0 +1,76 @@ +import React, { useRef } from 'react'; +import { Text, View, TouchableOpacity } from 'react-native'; +import { styled } from 'nativewind'; +import InvestmentContainer from './InvestmentContainer'; +import BottomSheet, { BottomSheetScrollView } from '@gorhom/bottom-sheet'; +import RecentlyViewedCard from './RecentlyViewedCards'; +import WideButton from '../../../components/WideButton'; +import { Portfolio } from '../../../types/investor'; + +const StyledTouchableOpacity = styled(TouchableOpacity); +const StyledView = styled(View); +const StyledText = styled(Text); + +const Investments = ({ portfolio, navigation }: { + portfolio: Portfolio + // This actually should be `any`, so disabling the linter rule + // eslint-disable-next-line @typescript-eslint/no-explicit-any + navigation: any; +}) => { + console.log(portfolio); + return ( + + Your Investments + {portfolio && + Object.keys(portfolio).map((projectId) => ( + navigation.navigate('Project')} key={projectId}> + + + + ))} + + Recently Viewed + {portfolio && + Object.keys(portfolio).map((projectId) => ( + navigation.navigate('Project')} key={projectId} className='mt-[3vh]'> + + + ))} + + + navigation.navigate('Project')} + > + + + ); +}; + +const BottomSheetComponent = ({ portfolio, navigation }: { + portfolio: Portfolio + // This actually should be `any`, so disabling the linter rule + // eslint-disable-next-line @typescript-eslint/no-explicit-any + navigation: any; +}) => { + const sheetRef = useRef(null); + + return ( + + + + + + + + ); +}; + +export default BottomSheetComponent; diff --git a/frontend/src/screens/home/components/InvestmentContainer.tsx b/frontend/src/screens/home/components/InvestmentContainer.tsx new file mode 100644 index 0000000..10d5b79 --- /dev/null +++ b/frontend/src/screens/home/components/InvestmentContainer.tsx @@ -0,0 +1,72 @@ +import React from 'react'; +import { Text, View, Image } from 'react-native'; +import { styled } from 'nativewind'; +import { useProject } from '../../../services/project'; + +const StyledView = styled(View); +const StyledText = styled(Text); +const StyledImage = styled(Image); + +const InvestmentStatus = ({ amount, status }) => { + return ( + + + ${amount.toLocaleString()} + + + {status} + + + ); +}; + +const InvestmentImageAndAddress = ({ image, street, city, state }) => { + return ( + + + + {street} + + {city}, {state} + + + + ); +}; + +const InvestmentContainer = ({ projectId }) => { + console.log(projectId); + // Get the project using the id + const { project, isLoading } = useProject(projectId); + // console.log(project); + if (isLoading) { + return Loading ...; + } + + // const projectStatus = project? + + return ( + + + + + + + ); +}; + +export default InvestmentContainer; diff --git a/frontend/src/screens/home/components/RecentlyViewedCards.tsx b/frontend/src/screens/home/components/RecentlyViewedCards.tsx new file mode 100644 index 0000000..e32331e --- /dev/null +++ b/frontend/src/screens/home/components/RecentlyViewedCards.tsx @@ -0,0 +1,111 @@ +import React from 'react'; +import { Text, View, Image } from 'react-native'; +import { styled } from 'nativewind'; +import Card from '../../../components/Card'; +import ProgressBar from '../../../components/ProgressBar'; +import StatusTag from '../components/StatusTag'; +import { useProject, useProjectTotalFunded } from '../../../services/project'; + +const StyledView = styled(View); +const StyledText = styled(Text); +const StyledImage = styled(Image); + +// Card component for recently viewed Projects +const RecentlyViewedCard = ({ projectId }: { projectId: string }) => { + // Get project data + const { project, isLoading } = useProject(projectId); + + // Get total project funding + const totalFunding = useProjectTotalFunded(projectId); + + if (isLoading) { + return Loading ...; + } + + // recently viewed card tag + const CardTag = () => { + let iconRoute; + if (project.milestone === 'Sold') { + iconRoute = require('../../../../assets/images/celebration.png'); + } else if (project.milestone === 'Funding') { + iconRoute = require('../../../../assets/images/money-success.png'); + } else if (project.milestone === 'Construction Complete') { + iconRoute = require('../../../../assets/images/house.png'); + } else if (project.milestone === 'Operational') { + iconRoute = require('../../../../assets/images/maps_home_work.png'); + } else if (project.milestone === 'Construction Started') { + iconRoute = require('../../../../assets/images/handyman.png'); + } else if (project.milestone === 'Permitting Secured') { + iconRoute = require('../../../../assets/images/topic.png'); + } else if (project.milestone === 'Design Complete') { + iconRoute = require('../../../../assets/images/design_services.png'); + } else { + iconRoute = require('../../../../assets/images/landscape.png'); + } + + let intent: 'InProgressGreen' | 'InProgressNeutral' | 'Sold' | 'Funding' | undefined; + if (project.milestone === 'Sold') { + intent = 'Sold'; + } else if (project.milestone === 'Funding') { + intent = 'Funding'; + } else if ( + project.milestone === 'Construction Complete' || + project.milestone === 'Operational' + ) { + intent = 'InProgressGreen'; + } else { + intent = 'InProgressNeutral'; + } + + return ( + + + + ); + }; + + const ProjectInformation = () => { + return ( + + {project?.street} + + {project?.locality}, {project?.state}{' '} + + + {project?.title} + + + ); + }; + return ( + + + + + + + + + + + {project.milestone === 'Funding' && ( + + + + )} + + ); +}; + +export default RecentlyViewedCard; + +{ + /* }>{status} */ +} diff --git a/frontend/src/screens/home/components/StatusTag.tsx b/frontend/src/screens/home/components/StatusTag.tsx new file mode 100644 index 0000000..b110da4 --- /dev/null +++ b/frontend/src/screens/home/components/StatusTag.tsx @@ -0,0 +1,102 @@ +import React from 'react'; +import { Text, Image, ImageSourcePropType, View } from 'react-native'; +import { styled } from 'nativewind'; +import { cva, type VariantProps } from 'class-variance-authority'; + +const StyledView = styled(View); +const StyledText = styled(Text); +const StyledImage = styled(Image); + +//variants for different button styles +const statusTagVariants = cva('button', { + variants: { + intent: { + //InProgress button + InProgressGreen: [ + 'rounded-lg', + 'flex', + 'items-center', + 'justify-center', + 'bg-mint', + 'flex-row', + ], + InProgressNeutral: [ + 'rounded-lg', + 'flex', + 'items-center', + 'justify-center', + 'flex-shrink', + 'bg-gray-200', + 'flex-row', + ], + //Funding button + Funding: [ + 'border-borderPrimary', + 'border-x-[0.3vw]', + 'border-y-[0.3vw]', + 'rounded-lg', + 'flex', + 'items-center', + 'justify-center', + 'w-[20vw]', + 'flex-row', + ], + Sold: [ + 'rounded-lg', + 'w-[20vw]', + 'flex', + 'items-center', + 'justify-center', + 'flex-row', + 'bg-success', + ], + }, + }, +}); + +//variants for different button text styles +const statusTagTextVariants = cva('text', { + variants: { + intent: { + InProgressNeutral: [ + 'text-[2.5vw]', + 'font-sourceSans3', + 'text-gray-600', + 'px-[1vw]', + 'py-[2vw]', + ], + InProgressGreen: ['text-[2.5vw]', 'font-sourceSans3', 'text-success', 'px-[1vw]', 'py-[2vw]'], + Funding: ['text-[2.5vw]', 'font-sourceSans3', 'text-success', 'px-[1vw]', 'py-[2vw]'], + Sold: ['text-[2.5vw]', 'font-sourceSans3', 'text-white', 'px-[1vw]', 'py-[2vw]'], + }, + }, +}); + +export interface TagProps + extends React.ButtonHTMLAttributes, + VariantProps { + //name of button + name: string; + //route to button's icon + iconRoute: ImageSourcePropType; + // This actually should be `any`, so disabling the linter rule + // eslint-disable-next-line @typescript-eslint/no-explicit-any + intent: 'InProgressGreen' | 'InProgressNeutral' | 'Funding' | 'Sold'; +} + +/** + * Wide button component + * @param name name of button. + * @param iconRoute route to button's icon. + * @param intent button variant (funding, sold, in progress). + */ +const StatusTag: React.FC = ({ name, iconRoute, intent }) => { + return ( + + + {name} + + ); +}; + +export default StatusTag; diff --git a/frontend/src/screens/home/portfolioValue.tsx b/frontend/src/screens/home/components/portfolioValue.tsx similarity index 77% rename from frontend/src/screens/home/portfolioValue.tsx rename to frontend/src/screens/home/components/portfolioValue.tsx index d938833..6e765bd 100644 --- a/frontend/src/screens/home/portfolioValue.tsx +++ b/frontend/src/screens/home/components/portfolioValue.tsx @@ -1,21 +1,24 @@ -/* import React from 'react'; import { Image, Text, View, TouchableOpacity } from 'react-native'; import { NavigationScreenProp } from 'react-navigation'; import { styled } from 'nativewind'; -import WideButton from '../../components/WideButton'; +import WideButton from '../../../components/WideButton'; const StyledView = styled(View); const StyledText = styled(Text); const StyledImage = styled(Image); //Button to add funds to the account -const AddFundsButton = ({ navigation }) => { +const AddFundsButton = ({ navigation }: + {// This actually should be `any`, so disabling the linter rule + // eslint-disable-next-line @typescript-eslint/no-explicit-any + navigation: NavigationScreenProp; +}) => { return ( navigation.navigate('Profile')} intent='secondary' > ); @@ -26,8 +29,8 @@ const PortfolioButton = ({ navigation }) => { return ( navigation.navigate('Portfolio')} intent='primary' > ); @@ -37,7 +40,7 @@ const PortfolioReturns = ({ portfolioChange }) => { return ( @@ -68,7 +71,7 @@ const PortfolioMoreDetailsIcon = ({ navigation }) => { navigation.navigate('secondScreen')}> @@ -76,7 +79,11 @@ const PortfolioMoreDetailsIcon = ({ navigation }) => { ); }; -const PortfolioButtons = ({ navigation }) => { +const PortfolioButtons = ({ navigation }: { + // This actually should be `any`, so disabling the linter rule + // eslint-disable-next-line @typescript-eslint/no-explicit-any + navigation: NavigationScreenProp; +}) => { return ( @@ -116,4 +123,3 @@ const PortfolioValue = ({ }; export default PortfolioValue; -*/ \ No newline at end of file diff --git a/frontend/src/screens/home/welcomeBlock.tsx b/frontend/src/screens/home/components/welcomeBlock.tsx similarity index 91% rename from frontend/src/screens/home/welcomeBlock.tsx rename to frontend/src/screens/home/components/welcomeBlock.tsx index c75cd27..a109328 100644 --- a/frontend/src/screens/home/welcomeBlock.tsx +++ b/frontend/src/screens/home/components/welcomeBlock.tsx @@ -1,42 +1,42 @@ -import React from 'react'; -import { Image, Text, View } from 'react-native'; -import { styled } from 'nativewind'; - -const StyledView = styled(View); -const StyledText = styled(Text); -const StyledImage = styled(Image); - -const NotificationIconBlock = () => { - return ( - - - - - - ); -}; - -const WelcomeTextBlock = ({ name }: { name: string }) => { - return ( - - Hello {name}! - Welcome back - - ); -}; - -const WelcomeBlock = ({ name }: { name: string }) => { - return ( - - - - - - - ); -}; - -export default WelcomeBlock; +import React from 'react'; +import { Image, Text, View } from 'react-native'; +import { styled } from 'nativewind'; + +const StyledView = styled(View); +const StyledText = styled(Text); +const StyledImage = styled(Image); + +const NotificationIconBlock = () => { + return ( + + + + + + ); +}; + +const WelcomeTextBlock = ({ name }: { name: string }) => { + return ( + + Hello {name}! + Welcome back + + ); +}; + +const WelcomeBlock = ({ name }: { name: string }) => { + return ( + + + + + + + ); +}; + +export default WelcomeBlock; diff --git a/frontend/src/screens/home/home.tsx b/frontend/src/screens/home/home.tsx index 154d749..561f893 100644 --- a/frontend/src/screens/home/home.tsx +++ b/frontend/src/screens/home/home.tsx @@ -1,128 +1,48 @@ -import React from 'react'; -import { Image, Text, View, TouchableOpacity, Button } from 'react-native'; +import React, { useState, useEffect } from 'react'; +import { View } from 'react-native'; import { NavigationScreenProp } from 'react-navigation'; -// import { NavigationScreenProp } from 'react-navigation'; import { styled } from 'nativewind'; -import { useContributors } from '../../services/contributor'; - +import PortfolioValue from './components/portfolioValue'; +import WelcomeBlock from './components/welcomeBlock'; +import BottomSheetComponent from './components/BottomSheetComponent'; +import { GestureHandlerRootView } from 'react-native-gesture-handler'; +import 'react-native-url-polyfill/auto'; +import { useInvestorProfile, useInvestorPortfolio } from '../../services/investor'; interface HomeScreenProps { // This actually should be `any`, so disabling the linter rule // eslint-disable-next-line @typescript-eslint/no-explicit-any navigation: NavigationScreenProp; } -// interface HomeScreenProps { -// // This actually should be `any`, so disabling the linter rule -// // eslint-disable-next-line @typescript-eslint/no-explicit-any -// navigation: NavigationScreenProp; -// } const StyledView = styled(View); -const StyledText = styled(Text); export default function HomeScreen({ navigation }: HomeScreenProps) { - console.log("Hello, world"); + const userProfile = useInvestorProfile(); + const [totalInvested, setTotalInvested] = useState(0); + const { portfolio } = useInvestorPortfolio(); - async function getEndPoint() { - try { - console.log(await useContributors()); + useEffect(() => { + if (portfolio) { + // Sum up the total invested amount + const total = Object.values(portfolio).reduce((sum, value) => sum + value, 0); + setTotalInvested(total); } - catch (error) { - console.log(error); - } - } - - getEndPoint(); - - return (<>); - // - // {/* Some dummy image */} - // - // - // - // {/* Some dummy button */} - // {}} - // disabled={false} - // /> - // {}} - // disabled={false} - // /> - // {}} - // disabled={true} - // /> - // {}} - // isPassword={false} - // /> - // {}} - // /> + }, [portfolio]); - - // - // - // - // - // - // {/* Some dummy image */} - // - // - // {/* Some dummy button */} - - // - // - // navigation.navigate('secondScreen')}> - // - // - // Dummy page - // - // - // - // navigation.navigate('profileScreen')}> - // - // - // Profile Page - // - // - // - // - // - // - // - // - // - // - // **/ - // ); + return ( + + + + + + + + + + ); } diff --git a/frontend/src/screens/home/styles.ts b/frontend/src/screens/home/styles.ts index bd3471a..0bedc00 100644 --- a/frontend/src/screens/home/styles.ts +++ b/frontend/src/screens/home/styles.ts @@ -1,12 +1,12 @@ -import { StyleSheet, Dimensions } from 'react-native'; - -const height = Dimensions.get('window').height; - -export default StyleSheet.create({ - imageStyle: { - height: height / 4, - resizeMode: 'contain', - marginTop: height / 20, - marginBottom: height / 20, - }, -}); +import { StyleSheet, Dimensions } from 'react-native'; + +const height = Dimensions.get('window').height; + +export default StyleSheet.create({ + imageStyle: { + height: height / 4, + resizeMode: 'contain', + marginTop: height / 20, + marginBottom: height / 20, + }, +}); diff --git a/frontend/src/screens/login/WelcomeScreen.tsx b/frontend/src/screens/login/WelcomeScreen.tsx index b638bdb..cd9b83c 100644 --- a/frontend/src/screens/login/WelcomeScreen.tsx +++ b/frontend/src/screens/login/WelcomeScreen.tsx @@ -10,31 +10,38 @@ const StyledImage = styled(Image); export default function WelcomeScreen({ navigation }) { return ( - + - + Providing the tools you need to make your first investments in real estate. {/* Some dummy image, not sure how this works */} - + - + - + > + Sign Up + + + > + Login + ); diff --git a/frontend/src/screens/login/components/RadioButtonComponent.tsx b/frontend/src/screens/login/components/RadioButtonComponent.tsx index 674c7e4..bac6966 100644 --- a/frontend/src/screens/login/components/RadioButtonComponent.tsx +++ b/frontend/src/screens/login/components/RadioButtonComponent.tsx @@ -12,9 +12,13 @@ const RadioButtonComponent = ({ label, selected, onPress }) => ( onPress={onPress} className={`flex-row items-center justify-between mb-4 p-4 border border-gray-300 rounded-lg shadow-md w-full max-w-md ${selected ? 'bg-primary/10 border-primary' : 'bg-white border-gray-300'}`} > - {label} - - {selected && } + + {label} + + + {selected && } ); diff --git a/frontend/src/screens/login/signup_flow/ConnectAccountsScreen.tsx b/frontend/src/screens/login/signup_flow/ConnectAccountsScreen.tsx index b6b4488..257489f 100644 --- a/frontend/src/screens/login/signup_flow/ConnectAccountsScreen.tsx +++ b/frontend/src/screens/login/signup_flow/ConnectAccountsScreen.tsx @@ -4,7 +4,6 @@ import { styled } from 'nativewind'; import Button from '../../../components/Button'; import ProgressBar from '../../../components/ProgressBar'; - const StyledView = styled(View); const StyledText = styled(Text); const StyledKeyboardAvoidingView = styled(KeyboardAvoidingView); @@ -13,43 +12,40 @@ const StyledScrollView = styled(ScrollView); export default function ConnectAccountsScreen({ navigation }) { return ( - - - + + {/* Progress Bar */} - - + + {/* Connect Accounts Section */} - - Connect Accounts - + + Connect Accounts + Connect your bank accounts to proceed. (Plaid integration coming soon) {/* Placeholder for Plaid integration */} - + [Plaid Integration Here] {/* Continue Button */} - + + > + Continue + - diff --git a/frontend/src/screens/login/signup_flow/EmailInputScreen.tsx b/frontend/src/screens/login/signup_flow/EmailInputScreen.tsx index d15c959..3633d80 100644 --- a/frontend/src/screens/login/signup_flow/EmailInputScreen.tsx +++ b/frontend/src/screens/login/signup_flow/EmailInputScreen.tsx @@ -1,4 +1,4 @@ -import React, {useState } from 'react'; +import React, { useState } from 'react'; import { View, Text, KeyboardAvoidingView, Platform, ScrollView, TextInput } from 'react-native'; import { styled } from 'nativewind'; import Button from '../../../components/Button'; @@ -27,42 +27,41 @@ export default function EmailInputScreen({ navigation }) { behavior={Platform.OS === 'ios' ? 'padding' : 'height'} keyboardVerticalOffset={80} > - - - + + {/* Progress Bar */} - - + + {/* Email Input Section */} - - Let's start with your email - + + + Let's start with your email + + You’ll use this email to log in next time. setEmail(text)} - keyboardType="email-address" - > - - + keyboardType='email-address' + > {/* Continue Button */} - + + > + Continue + - diff --git a/frontend/src/screens/login/signup_flow/PasswordInputScreen.tsx b/frontend/src/screens/login/signup_flow/PasswordInputScreen.tsx index 75c49d5..82062dd 100644 --- a/frontend/src/screens/login/signup_flow/PasswordInputScreen.tsx +++ b/frontend/src/screens/login/signup_flow/PasswordInputScreen.tsx @@ -1,4 +1,4 @@ -import React, {useState } from 'react'; +import React, { useState } from 'react'; import { View, Text, KeyboardAvoidingView, Platform, ScrollView, TextInput } from 'react-native'; import { styled } from 'nativewind'; import Button from '../../../components/Button'; @@ -6,7 +6,6 @@ import ProgressBar from '../../../components/ProgressBar'; import TextInputComponent from '../components/TextInputComponent'; import { useAuth } from '../../../context/AuthContext'; - const StyledView = styled(View); const StyledText = styled(Text); const StyledKeyboardAvoidingView = styled(KeyboardAvoidingView); @@ -23,46 +22,46 @@ export default function PasswordInputScreen({ navigation }) { return ( - - - + + {/* Progress Bar */} - - + + {/* Password Input Section */} - - Create a password - + + + Create a password + + Choose a strong password for your account. setPassword(text)} isPassword={true} - > - + > {/* Continue Button */} - + + > + Continue + - diff --git a/frontend/src/screens/login/signup_flow/UserDetailsScreen.tsx b/frontend/src/screens/login/signup_flow/UserDetailsScreen.tsx index e024329..9703f05 100644 --- a/frontend/src/screens/login/signup_flow/UserDetailsScreen.tsx +++ b/frontend/src/screens/login/signup_flow/UserDetailsScreen.tsx @@ -1,4 +1,4 @@ -import React, {useState } from 'react'; +import React, { useState } from 'react'; import { View, Text, KeyboardAvoidingView, Platform, ScrollView, TextInput } from 'react-native'; import { styled } from 'nativewind'; import Button from '../../../components/Button'; @@ -6,7 +6,6 @@ import ProgressBar from '../../../components/ProgressBar'; import { useAuth } from '../../../context/AuthContext'; import TextInputComponent from '../components/TextInputComponent'; - const StyledView = styled(View); const StyledText = styled(Text); const StyledKeyboardAvoidingView = styled(KeyboardAvoidingView); @@ -25,56 +24,55 @@ export default function UserDetailsScreen({ navigation }) { return ( - - - + + {/* Progress Bar */} - - + + {/* User Details Input Section */} - - A bit about you - + + + A bit about you + + We need your first and last name to get started. setFirstName(input)} autoCapitalize='words' autoFocus={true} - > - + > setLastName(input)} autoCapitalize='words' autoFocus={false} - > - + > {/* Continue Button */} - + + > + Continue + - diff --git a/frontend/src/screens/portfolio/PortfolioScreen.tsx b/frontend/src/screens/portfolio/PortfolioScreen.tsx index 1404182..9078705 100644 --- a/frontend/src/screens/portfolio/PortfolioScreen.tsx +++ b/frontend/src/screens/portfolio/PortfolioScreen.tsx @@ -1,5 +1,5 @@ import React, { useState } from 'react'; -import { Image, Text, View, TouchableOpacity} from 'react-native'; +import { Image, Text, View, TouchableOpacity } from 'react-native'; import { NavigationScreenProp } from 'react-navigation'; import { styled } from 'nativewind'; import { ScrollView } from 'react-native'; @@ -17,18 +17,13 @@ const StyledView = styled(View); const StyledText = styled(Text); const StyledScrollView = styled(ScrollView); const StyledImage = styled(Image); -const StyledTouchableOpacity= styled(TouchableOpacity); - - - +const StyledTouchableOpacity = styled(TouchableOpacity); export default function PorfolioScreen({ navigation }: PortfolioScreenProps) { - const [activeTab, setActiveTab] = useState('Your Projects'); return ( - {/* Padding */} @@ -44,119 +39,129 @@ export default function PorfolioScreen({ navigation }: PortfolioScreenProps) { - + {/* Tab section */} - - setActiveTab('Your Projects')} className={`items-center py-2 rounded-t-lg ${activeTab === 'Your Projects' ? 'bg-green-900' : 'bg-white'}`}> - - Your Projects - - - - - setActiveTab('Updates')} className={` items-center py-2 rounded-t-lg ${activeTab === 'Updates' ? 'bg-green-900' : 'bg-white'}`}> - - Updates - - - + + setActiveTab('Your Projects')} + className={`items-center py-2 rounded-t-lg ${activeTab === 'Your Projects' ? 'bg-green-900' : 'bg-white'}`} + > + + Your Projects + + + + + setActiveTab('Updates')} + className={` items-center py-2 rounded-t-lg ${activeTab === 'Updates' ? 'bg-green-900' : 'bg-white'}`} + > + + Updates + + + - + {/*Your Projects*/} - {activeTab === 'Your Projects' ? ( - - - {' '} - 8 Total Investments - - - - - - - - - - ) - : - ( - {/* Updates */} - - + {activeTab === 'Your Projects' ? ( + + + {' '} + 8 Total Investments + + + + + + + + + + + ) : ( + + {/* Updates */} + + )} - - - - - + ); diff --git a/frontend/src/screens/portfolio/components/PortfolioDetails.tsx b/frontend/src/screens/portfolio/components/PortfolioDetails.tsx index bea2987..f32eb33 100644 --- a/frontend/src/screens/portfolio/components/PortfolioDetails.tsx +++ b/frontend/src/screens/portfolio/components/PortfolioDetails.tsx @@ -6,62 +6,60 @@ const StyledView = styled(View); const StyledText = styled(Text); const StyledImage = styled(Image); -const PortfolioDetails = ()=> { - return ( - - {/* Top Part */} - - - Net Portfolio Value - - - - - $12,345.67 - - $350.23 - + 9.70% - Total Return - +const PortfolioDetails = () => { + return ( + + {/* Top Part */} + + + Net Portfolio Value + + + + + $12,345.67 + + $350.23 + + 9.70% + Total Return + + + {/* Four grid */} + + + + + Market Value + $10,000.00 + + + + + Cash Value + $2,345.67 - {/* Four grid */} - - - - - Market Value - $10,000.00 - - - - - Cash Value - $2,345.67 - - - - - - - Total Positions - 11 - - - - - Exp Maturity - 12.5 Years - - + + + + + + Total Positions + 11 + + + + Exp Maturity + 12.5 Years - + - - ); + + + ); }; -export default PortfolioDetails; \ No newline at end of file +export default PortfolioDetails; diff --git a/frontend/src/screens/portfolio/components/PortfolioItem.tsx b/frontend/src/screens/portfolio/components/PortfolioItem.tsx index 80f7a81..88c5c50 100644 --- a/frontend/src/screens/portfolio/components/PortfolioItem.tsx +++ b/frontend/src/screens/portfolio/components/PortfolioItem.tsx @@ -2,72 +2,92 @@ import React from 'react'; import { View, Text, Image, ImageBackground } from 'react-native'; import { styled } from 'nativewind'; - const StyledView = styled(View); const StyledText = styled(Text); interface PortfolioItemProps { - address: string; - location: string; - price: number; - duration: string; - invested: number; - completion: number; - imageUrl: string; + address: string; + location: string; + price: number; + duration: string; + invested: number; + completion: number; + imageUrl: string; } -const PortfolioItem = ({address, location, price, duration, invested, completion, imageUrl} : PortfolioItemProps )=> { - return ( - - - {/* Left Side of the Card*/} - - - 333 Market Street - San Francisco, CA - - Commercial Development - - - Land Control Secured - - - - Value - $250.00 - - - Exp Return - 5.12% - - - - - - {/* Right Side of the Card*/} - - - - - - - Time Line - 6 Years - - +const PortfolioItem = ({ + address, + location, + price, + duration, + invested, + completion, + imageUrl, +}: PortfolioItemProps) => { + return ( + + + {/* Left Side of the Card*/} + + + 333 Market Street + + San Francisco, CA + + + + Commercial Development + + + + + Land Control Secured + + + + + Value + + + $250.00 + + + + + Exp Return + + 5.12% + + + + + {/* Right Side of the Card*/} + + + + + + + Time Line + + 6 Years + - ); + + + ); }; -export default PortfolioItem; \ No newline at end of file +export default PortfolioItem; diff --git a/frontend/src/screens/portfolio/components/PortfolioUpdateCard.tsx b/frontend/src/screens/portfolio/components/PortfolioUpdateCard.tsx index 0541e03..44f5deb 100644 --- a/frontend/src/screens/portfolio/components/PortfolioUpdateCard.tsx +++ b/frontend/src/screens/portfolio/components/PortfolioUpdateCard.tsx @@ -8,36 +8,36 @@ const StyledView = styled(View); const StyledText = styled(Text); interface UpdateCardProps { - topText: string; - bottomText: string; - quantity: string; + topText: string; + bottomText: string; + quantity: string; } const UpdateCard = ({ topText, bottomText, quantity }: UpdateCardProps) => { - return ( - - - - - } - rightComponent={{quantity}} - spacing="mr-4" - containerStyle="flex-1" + return ( + + + - ); - }; - -export default UpdateCard; \ No newline at end of file + } + rightComponent={{quantity}} + spacing='mr-4' + containerStyle='flex-1' + /> + + ); +}; + +export default UpdateCard; diff --git a/frontend/src/screens/portfolio/components/PortfolioUpdateText.tsx b/frontend/src/screens/portfolio/components/PortfolioUpdateText.tsx index 9830395..692212f 100644 --- a/frontend/src/screens/portfolio/components/PortfolioUpdateText.tsx +++ b/frontend/src/screens/portfolio/components/PortfolioUpdateText.tsx @@ -6,18 +6,17 @@ const StyledView = styled(View); const StyledText = styled(Text); interface UpdateTextProps { - topText: string; - bottomText: string; + topText: string; + bottomText: string; } -const UpdateText = ({topText, bottomText} : UpdateTextProps )=> { - - return ( - - {topText} - {bottomText} - - ); +const UpdateText = ({ topText, bottomText }: UpdateTextProps) => { + return ( + + {topText} + {bottomText} + + ); }; - -export default UpdateText; \ No newline at end of file + +export default UpdateText; diff --git a/frontend/src/screens/profile/ProfileScreen.tsx b/frontend/src/screens/profile/ProfileScreen.tsx index 459410c..6fe715f 100644 --- a/frontend/src/screens/profile/ProfileScreen.tsx +++ b/frontend/src/screens/profile/ProfileScreen.tsx @@ -11,59 +11,83 @@ const StyledText = styled(Text); const StyledImage = styled(Image); interface ProfileScreenProps { - // This actually should be `any`, so disabling the linter rule - // eslint-disable-next-line @typescript-eslint/no-explicit-any - navigation: NavigationScreenProp; + // This actually should be `any`, so disabling the linter rule + // eslint-disable-next-line @typescript-eslint/no-explicit-any + navigation: NavigationScreenProp; } //Button to navigate to the portfolio page const EditProfileButton = ({ navigation }) => { - return ( - - - - ); - }; + return ( + + + + ); +}; export default function ProfileScreen({ navigation }: ProfileScreenProps) { - return( - - {/*Your Profile ...*/} - - - Your Profile - - {}}/> - - - - - Your Name - - - yourname@gmail.com - - - - - - - - - - - - - - - - - - - - + return ( + + {/*Your Profile ...*/} + + + Your Profile + + {}} /> + + + + Your Name + yourname@gmail.com + + + + + + + + + + + + - ); -} \ No newline at end of file + + + + + + + + ); +} diff --git a/frontend/src/screens/profile/components/NotificationButton.tsx b/frontend/src/screens/profile/components/NotificationButton.tsx index be29457..5ed92ff 100644 --- a/frontend/src/screens/profile/components/NotificationButton.tsx +++ b/frontend/src/screens/profile/components/NotificationButton.tsx @@ -1,15 +1,15 @@ import React from 'react'; -import { Pressable, View, Image } from "react-native"; +import { Pressable, View, Image } from 'react-native'; import { NavigationScreenProp } from 'react-navigation'; import { styled } from 'nativewind'; interface NotificationButtonProps { - // This actually should be `any`, so disabling the linter rule - // eslint-disable-next-line @typescript-eslint/no-explicit-any - navigation: NavigationScreenProp; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - onPress: any; - //Need to ask about type ^ + // This actually should be `any`, so disabling the linter rule + // eslint-disable-next-line @typescript-eslint/no-explicit-any + navigation: NavigationScreenProp; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + onPress: any; + //Need to ask about type ^ } const StyledView = styled(View); @@ -17,23 +17,22 @@ const StyledPressable = styled(Pressable); const StyledImage = styled(Image); const NotificationIconBlock = () => { - return ( - - - - + return ( + + + - ); - }; + + ); +}; -export default function NotificationButton({navigation}: NotificationButtonProps, onPress) { - return( - - - - ); -} \ No newline at end of file +export default function NotificationButton({ navigation }: NotificationButtonProps, onPress) { + return ( + + + + ); +} diff --git a/frontend/src/screens/profile/components/ProfilePageNavigator.tsx b/frontend/src/screens/profile/components/ProfilePageNavigator.tsx index 62b060d..054b6d4 100644 --- a/frontend/src/screens/profile/components/ProfilePageNavigator.tsx +++ b/frontend/src/screens/profile/components/ProfilePageNavigator.tsx @@ -1,33 +1,38 @@ import React from 'react'; -import { TouchableOpacity, View, Text, Image, ImageSourcePropType} from "react-native"; +import { TouchableOpacity, View, Text, Image, ImageSourcePropType } from 'react-native'; import { NavigationScreenProp } from 'react-navigation'; import { styled } from 'nativewind'; interface ProfilePageNavigatorProps { - // This actually should be `any`, so disabling the linter rule - // eslint-disable-next-line @typescript-eslint/no-explicit-any - navigation: NavigationScreenProp; - pageName: string; - //route to button's icon - iconRoute?: ImageSourcePropType; + // This actually should be `any`, so disabling the linter rule + // eslint-disable-next-line @typescript-eslint/no-explicit-any + navigation: NavigationScreenProp; + pageName: string; + //route to button's icon + iconRoute?: ImageSourcePropType; } const StyledView = styled(View); const StyledText = styled(Text); const StyledImage = styled(Image); -export default function ProfilePageNavigator({ navigation, pageName, iconRoute }: ProfilePageNavigatorProps) { - return( - navigation.navigate({pageName})}> - - - {iconRoute && } - - {pageName} - - - - - - ); -} \ No newline at end of file +export default function ProfilePageNavigator({ + navigation, + pageName, + iconRoute, +}: ProfilePageNavigatorProps) { + return ( + navigation.navigate({ pageName })}> + + + {iconRoute && } + {pageName} + + + + + ); +} diff --git a/frontend/src/screens/project/ProjectImagesScreen.tsx b/frontend/src/screens/project/ProjectImagesScreen.tsx index 304416a..e9b453e 100644 --- a/frontend/src/screens/project/ProjectImagesScreen.tsx +++ b/frontend/src/screens/project/ProjectImagesScreen.tsx @@ -1,5 +1,14 @@ import React, { useState } from 'react'; -import { Image, Text, View, TouchableOpacity, Button, DimensionValue, Dimensions, ScrollView } from 'react-native'; +import { + Image, + Text, + View, + TouchableOpacity, + Button, + DimensionValue, + Dimensions, + ScrollView, +} from 'react-native'; import { NavigationScreenProp } from 'react-navigation'; import { styled } from 'nativewind'; @@ -9,9 +18,9 @@ import { useDerivedValue, useSharedValue } from 'react-native-reanimated'; import { Zoomable } from '@likashefqet/react-native-image-zoom'; interface ProjectImagesScreenProps { - // This actually should be `any`, so disabling the linter rule - // eslint-disable-next-line @typescript-eslint/no-explicit-any - navigation: NavigationScreenProp; + // This actually should be `any`, so disabling the linter rule + // eslint-disable-next-line @typescript-eslint/no-explicit-any + navigation: NavigationScreenProp; } const StyledView = styled(View); @@ -20,55 +29,63 @@ const StyledImage = styled(Image); const StyledScrollView = styled(ScrollView); export default function ProjectImagesScreen({ navigation }: ProjectImagesScreenProps) { - const { project, isLoading } = useProject('c3733692-5a86-441f-8ad0-9c32c648bb72'); - const ref = React.useRef(null); - - const progress = useSharedValue(0); + const { project, isLoading } = useProject('c3733692-5a86-441f-8ad0-9c32c648bb72'); + const ref = React.useRef(null); - if (isLoading) { - return Loading ... - } + const progress = useSharedValue(0); - return ( - - - { - progress.value = absoluteProgress - }} - renderItem={({ item }) => ( - - - - - - )} + if (isLoading) { + return Loading ...; + } + + return ( + + + { + progress.value = absoluteProgress; + }} + renderItem={({ item }) => ( + + + + - - - - {project.images.map((item, ind, arr) => ( - {ref.current?.scrollTo({ count: ind - progress.value, animated: true})}}> - - - - - ))} - - + )} + /> + + + + + {project.images.map((item, ind, arr) => ( + { + ref.current?.scrollTo({ count: ind - progress.value, animated: true }); + }} + > + + + + + ))} - ); + + + ); } diff --git a/frontend/src/screens/project/ProjectMapScreen.tsx b/frontend/src/screens/project/ProjectMapScreen.tsx index 34a11db..f0a87cc 100644 --- a/frontend/src/screens/project/ProjectMapScreen.tsx +++ b/frontend/src/screens/project/ProjectMapScreen.tsx @@ -7,25 +7,30 @@ import { useProject, useProjectTotalFunded } from '../../services/project'; import MapView, { Marker } from 'react-native-maps'; interface ProjectMapScreenProps { - // This actually should be `any`, so disabling the linter rule - // eslint-disable-next-line @typescript-eslint/no-explicit-any - navigation: NavigationScreenProp; + // This actually should be `any`, so disabling the linter rule + // eslint-disable-next-line @typescript-eslint/no-explicit-any + navigation: NavigationScreenProp; } const StyledMapView = styled(MapView); export default function ProjectMapScreen({ navigation }: ProjectMapScreenProps) { - const { project, isLoading } = useProject('c3733692-5a86-441f-8ad0-9c32c648bb72'); + const { project, isLoading } = useProject('c3733692-5a86-441f-8ad0-9c32c648bb72'); - if (isLoading) { - return Loading ... - } + if (isLoading) { + return Loading ...; + } - const mapRegion = {latitude: project.latitude, longitude: project.longitude, latitudeDelta: 0.005, longitudeDelta: 0.005}; + const mapRegion = { + latitude: project.latitude, + longitude: project.longitude, + latitudeDelta: 0.005, + longitudeDelta: 0.005, + }; - return ( - - - - ); + return ( + + + + ); } diff --git a/frontend/src/screens/project/ProjectScreen.tsx b/frontend/src/screens/project/ProjectScreen.tsx index 353b2e2..4464f49 100644 --- a/frontend/src/screens/project/ProjectScreen.tsx +++ b/frontend/src/screens/project/ProjectScreen.tsx @@ -1,5 +1,13 @@ import React from 'react'; -import { Image, Text, View, TouchableOpacity, Button, DimensionValue, ScrollView } from 'react-native'; +import { + Image, + Text, + View, + TouchableOpacity, + Button, + DimensionValue, + ScrollView, +} from 'react-native'; import { NavigationScreenProp } from 'react-navigation'; import { styled } from 'nativewind'; @@ -7,9 +15,9 @@ import { useProject, useProjectTotalFunded } from '../../services/project'; import MapView, { Marker } from 'react-native-maps'; interface ProjectScreenProps { - // This actually should be `any`, so disabling the linter rule - // eslint-disable-next-line @typescript-eslint/no-explicit-any - navigation: NavigationScreenProp; + // This actually should be `any`, so disabling the linter rule + // eslint-disable-next-line @typescript-eslint/no-explicit-any + navigation: NavigationScreenProp; } const StyledView = styled(View); @@ -20,133 +28,158 @@ const StyledTouchableOpacity = styled(TouchableOpacity); const StyledMapView = styled(MapView); export default function ProjectScreen({ navigation }: ProjectScreenProps) { - const { project, isLoading } = useProject('c3733692-5a86-441f-8ad0-9c32c648bb72'); - const { projectTotalFunded, isLoading: isProjectTotalFundedLoading } = useProjectTotalFunded('c3733692-5a86-441f-8ad0-9c32c648bb72'); - - if (isLoading || isProjectTotalFundedLoading) { - return Loading ... - } - - const firstTitle = `${project.premise} ${project.street}` - const secondTitle = `${project.locality}, ${project.state}` - - const formatCents = (x: number) => { - return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(x / 100); - } - - const fundingProgress: DimensionValue = `${(projectTotalFunded / project.funding_goal_cents).toFixed(0)}%` as DimensionValue; - - const propertyDetails = [ - ["Property Type", "Residential"], - ["Investment Strategy", "Value-Add"], - ["Investment Type", "Equity"], - ["Estimated First Distribution", "8/2025"], - ["Estimated Hold Period", "20 Months"] - ]; - - const numberOfImages = project.images.length; - const imageButtonText = numberOfImages > 20 ? "20+ Images" : `${numberOfImages} Images`; - const mapRegion = {latitude: project.latitude, longitude: project.longitude, latitudeDelta: 0.001, longitudeDelta: 0.001}; - - return ( - - { navigation.navigate('project-images')}}> - - - - - - - - - - - - {imageButtonText} - - - - - - { navigation.navigate('project-map') }}> - - - - - - { firstTitle } - - - - { secondTitle } - - - - - Status: - - - In Progress - - + const { project, isLoading } = useProject('c3733692-5a86-441f-8ad0-9c32c648bb72'); + const { projectTotalFunded, isLoading: isProjectTotalFundedLoading } = useProjectTotalFunded( + 'c3733692-5a86-441f-8ad0-9c32c648bb72', + ); + + if (isLoading || isProjectTotalFundedLoading) { + return Loading ...; + } + + const firstTitle = `${project.premise} ${project.street}`; + const secondTitle = `${project.locality}, ${project.state}`; + + const formatCents = (x: number) => { + return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(x / 100); + }; + + const fundingProgress: DimensionValue = + `${(projectTotalFunded / project.funding_goal_cents).toFixed(0)}%` as DimensionValue; + + const propertyDetails = [ + ['Property Type', 'Residential'], + ['Investment Strategy', 'Value-Add'], + ['Investment Type', 'Equity'], + ['Estimated First Distribution', '8/2025'], + ['Estimated Hold Period', '20 Months'], + ]; + + const numberOfImages = project.images.length; + const imageButtonText = numberOfImages > 20 ? '20+ Images' : `${numberOfImages} Images`; + const mapRegion = { + latitude: project.latitude, + longitude: project.longitude, + latitudeDelta: 0.001, + longitudeDelta: 0.001, + }; + + return ( + + { + navigation.navigate('project-images'); + }} + > + + + + + + + + + + + + + {imageButtonText} + - - - - - - Raised: { isProjectTotalFundedLoading ? "Loading..." : formatCents(projectTotalFunded) } - - - Goal: {formatCents(project.funding_goal_cents)} - - - - { navigation.navigate('project-invest') }}> - {/* For some reason tailwindclasses doesnt work here*/} - Invest - - - { navigation.navigate('project-updates') }}> - {/* For some reason tailwindclasses doesnt work here*/} - Updates - - - - - Description - - - - {project.description} - - - - - - {propertyDetails.map((val, idx, arr) => ( - - - {val[0]} - - - {val[1]} - - - ))} - - - ); + + + + { + navigation.navigate('project-map'); + }} + > + + + + + {firstTitle} + + {secondTitle} + + + Status: + In Progress + + + + + + + + Raised: {isProjectTotalFundedLoading ? 'Loading...' : formatCents(projectTotalFunded)} + + + Goal: {formatCents(project.funding_goal_cents)} + + + + { + navigation.navigate('project-invest'); + }} + > + + {' '} + {/* For some reason tailwindclasses doesnt work here*/} + Invest + + + { + navigation.navigate('project-updates'); + }} + > + + {' '} + {/* For some reason tailwindclasses doesnt work here*/} + Updates + + + + + Description + + + {project.description} + + + + + {propertyDetails.map((val, idx, arr) => ( + + {val[0]} + {val[1]} + + ))} + + + ); } diff --git a/frontend/src/services/investor.ts b/frontend/src/services/investor.ts index b83c1ec..f30e7ef 100644 --- a/frontend/src/services/investor.ts +++ b/frontend/src/services/investor.ts @@ -65,12 +65,20 @@ export const useInvestorPortfolio = () => { }; // GET investor's history of transactions -const getInvestorHistory = async (accessToken: string): Promise => { +const getInvestorHistory = async ( + accessToken: string, + offset: number, + limit: number, +): Promise => { try { const response = await axios.get(`${API_URL}/api/v1/investors/history`, { headers: { Authorization: `${accessToken}`, }, + params: { + limit, + offset, + }, }); return response.data; // Return the project if successful } catch (error) { @@ -79,12 +87,12 @@ const getInvestorHistory = async (accessToken: string): Promise } }; -export const useInvestorHistory = () => { +export const useInvestorHistory = (currentPage, itemsPerPage) => { const { session } = useAuth(); const { data: history, isLoading } = useQuery({ queryKey: ['investor_portfolio'], - queryFn: () => getInvestorHistory(session?.access_token), + queryFn: () => getInvestorHistory(session?.access_token, currentPage, itemsPerPage), }); return { diff --git a/frontend/src/types/contributor.ts b/frontend/src/types/contributor.ts index 039f757..796b826 100644 --- a/frontend/src/types/contributor.ts +++ b/frontend/src/types/contributor.ts @@ -1,6 +1,6 @@ -export interface Contributor { - id: number; - firstName: string; - lastName: string; - email: string; -} +export interface Contributor { + id: number; + firstName: string; + lastName: string; + email: string; +} diff --git a/frontend/src/types/env.d.ts b/frontend/src/types/env.d.ts index 2c97863..4a1184e 100644 --- a/frontend/src/types/env.d.ts +++ b/frontend/src/types/env.d.ts @@ -1,5 +1,5 @@ -declare module '@env' { - export const TS3_SUPABASE_PROJECT_URL: string; - export const TS3_SUPABASE_JWT_SECRET: string; - export const TS3_SUPABASE_API_KEY: string; -} +declare module '@env' { + export const TS3_SUPABASE_PROJECT_URL: string; + export const TS3_SUPABASE_JWT_SECRET: string; + export const TS3_SUPABASE_API_KEY: string; +} diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js index 50af67e..6003917 100644 --- a/frontend/tailwind.config.js +++ b/frontend/tailwind.config.js @@ -27,6 +27,7 @@ module.exports = { borderSelected: '#4B4B4B', brand50: '#CADEDB', success: '#0E9888', + mint: '#ECF3ED', warning: '#F7B418', error: '#D32246', brand: { diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index 8dc1b92..0e6371f 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -1,4 +1,4 @@ -{ - "compilerOptions": {}, - "extends": "expo/tsconfig.base" -} +{ + "compilerOptions": {}, + "extends": "expo/tsconfig.base" +} diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 357f263..afc8cb6 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -1227,10 +1227,10 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@^9.9.0", "@eslint/js@9.15.0": - version "9.15.0" - resolved "https://registry.npmjs.org/@eslint/js/-/js-9.15.0.tgz" - integrity sha512-tMTqrY+EzbXmKJR5ToI8lxu7jaN5EdmrBFJpQk5JmSlyLsx6o4t27r883K5xsLuCYCpfKBCGswMSWXsM+jB7lg== +"@eslint/js@^9.9.0", "@eslint/js@9.16.0": + version "9.16.0" + resolved "https://registry.npmjs.org/@eslint/js/-/js-9.16.0.tgz" + integrity sha512-tw2HxzQkrbeuvyj1tG2Yqq+0H9wGoI2IMk4EOsQeX+vmd75FtJAzf+gTA69WF+baUKRYQ3x2kbLE08js5OsTVg== "@eslint/object-schema@^2.1.4": version "2.1.4" @@ -1600,6 +1600,21 @@ find-up "^5.0.0" js-yaml "^4.1.0" +"@gorhom/bottom-sheet@^5.0.6": + version "5.0.6" + resolved "https://registry.npmjs.org/@gorhom/bottom-sheet/-/bottom-sheet-5.0.6.tgz" + integrity sha512-SI/AhPvgRfnCWN6/+wbE6TXwRE4X8F2fLyE4L/0bRwgE34Zenq585qLT139uEcfCIyovC2swC3ICqQpkmWEcFA== + dependencies: + "@gorhom/portal" "1.0.14" + invariant "^2.2.4" + +"@gorhom/portal@1.0.14": + version "1.0.14" + resolved "https://registry.npmjs.org/@gorhom/portal/-/portal-1.0.14.tgz" + integrity sha512-MXyL4xvCjmgaORr/rtryDNFy3kU4qUbKlwtQqqsygd0xX3mhKjOLn6mQK8wfu0RkoE0pBE0nAasRoHua+/QZ7A== + dependencies: + nanoid "^3.3.1" + "@humanfs/core@^0.19.1": version "0.19.1" resolved "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz" @@ -2353,15 +2368,15 @@ dependencies: "@supabase/node-fetch" "^2.6.14" -"@supabase/realtime-js@2.10.7": - version "2.10.7" - resolved "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.10.7.tgz" - integrity sha512-OLI0hiSAqQSqRpGMTUwoIWo51eUivSYlaNBgxsXZE7PSoWh12wPRdVt0psUMaUzEonSB85K21wGc7W5jHnT6uA== +"@supabase/realtime-js@2.10.9": + version "2.10.9" + resolved "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.10.9.tgz" + integrity sha512-0AjN65VDNIScZzrrPaVvlND4vbgVS+j9Wcy3zf7e+l9JY4IwCTahFenPLcKy9bkr7KY0wfB7MkipZPKxMaDnjw== dependencies: "@supabase/node-fetch" "^2.6.14" "@types/phoenix" "^1.5.4" "@types/ws" "^8.5.10" - ws "^8.14.2" + ws "^8.18.0" "@supabase/storage-js@2.7.1": version "2.7.1" @@ -2371,15 +2386,15 @@ "@supabase/node-fetch" "^2.6.14" "@supabase/supabase-js@^2.46.1": - version "2.46.1" - resolved "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.46.1.tgz" - integrity sha512-HiBpd8stf7M6+tlr+/82L8b2QmCjAD8ex9YdSAKU+whB/SHXXJdus1dGlqiH9Umy9ePUuxaYmVkGd9BcvBnNvg== + version "2.46.2" + resolved "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.46.2.tgz" + integrity sha512-5FEzYMZhfIZrMWEqo5/dQincvrhM+DeMWH3/okeZrkBBW1AJxblOQhnhF4/dfNYK25oZ1O8dAnnxZ9gQqdr40w== dependencies: "@supabase/auth-js" "2.65.1" "@supabase/functions-js" "2.4.3" "@supabase/node-fetch" "2.6.15" "@supabase/postgrest-js" "1.16.3" - "@supabase/realtime-js" "2.10.7" + "@supabase/realtime-js" "2.10.9" "@supabase/storage-js" "2.7.1" "@szmarczak/http-timer@^4.0.5": @@ -2389,17 +2404,17 @@ dependencies: defer-to-connect "^2.0.0" -"@tanstack/query-core@5.60.6": - version "5.60.6" - resolved "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.60.6.tgz" - integrity sha512-tI+k0KyCo1EBJ54vxK1kY24LWj673ujTydCZmzEZKAew4NqZzTaVQJEuaG1qKj2M03kUHN46rchLRd+TxVq/zQ== +"@tanstack/query-core@5.62.0": + version "5.62.0" + resolved "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.62.0.tgz" + integrity sha512-sx38bGrqF9bop92AXOvzDr0L9fWDas5zXdPglxa9cuqeVSWS7lY6OnVyl/oodfXjgOGRk79IfCpgVmxrbHuFHg== "@tanstack/react-query@^5.51.23": - version "5.61.3" - resolved "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.61.3.tgz" - integrity sha512-c3Oz9KaCBapGkRewu7AJLhxE9BVqpMcHsd3KtFxSd7FSCu2qGwqfIN37zbSGoyk6Ix9LGZBNHQDPI6GpWABnmA== + version "5.62.0" + resolved "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.62.0.tgz" + integrity sha512-tj2ltjAn2a3fs+Dqonlvs6GyLQ/LKVJE2DVSYW+8pJ3P6/VCVGrfqv5UEchmlP7tLOvvtZcOuSyI2ooVlR5Yqw== dependencies: - "@tanstack/query-core" "5.60.6" + "@tanstack/query-core" "5.62.0" "@testing-library/dom@^10.4.0": version "10.4.0" @@ -2416,9 +2431,9 @@ pretty-format "^27.0.2" "@testing-library/react-native@^12.6.0": - version "12.8.1" - resolved "https://registry.npmjs.org/@testing-library/react-native/-/react-native-12.8.1.tgz" - integrity sha512-/7PIFCpeqAD3j7nzKQhZtm1T6RR/O/tB1We7JHtYP5RpTBj8rPitEpt6xGrD8R0ymOh+DxDKK7Zovfv5uDSRWg== + version "12.9.0" + resolved "https://registry.npmjs.org/@testing-library/react-native/-/react-native-12.9.0.tgz" + integrity sha512-wIn/lB1FjV2N4Q7i9PWVRck3Ehwq5pkhAef5X5/bmQ78J/NoOsGbVY2/DG5Y9Lxw+RfE+GvSEh/fe5Tz6sKSvw== dependencies: jest-matcher-utils "^29.7.0" pretty-format "^29.7.0" @@ -2576,16 +2591,16 @@ "@types/node" "*" "@types/node@*": - version "22.9.3" - resolved "https://registry.npmjs.org/@types/node/-/node-22.9.3.tgz" - integrity sha512-F3u1fs/fce3FFk+DAxbxc78DF8x0cY09RRL8GnXLmkJ1jvx3TtPdWoTT5/NiYfI5ASqXBmfqJi9dZ3gxMx4lzw== + version "22.10.1" + resolved "https://registry.npmjs.org/@types/node/-/node-22.10.1.tgz" + integrity sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ== dependencies: - undici-types "~6.19.8" + undici-types "~6.20.0" "@types/phoenix@^1.5.4": - version "1.6.5" - resolved "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.6.5.tgz" - integrity sha512-xegpDuR+z0UqG9fwHqNoy3rI7JDlvaPh2TY47Fl80oq6g+hXT+c/LEuE43X48clZ6lOfANl5WrPur9fYO1RJ/w== + version "1.6.6" + resolved "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.6.6.tgz" + integrity sha512-PIzZZlEppgrpoT2QgbnDU+MMzuR6BbCjllj0bM70lWoejMeNJAxCchxnv7J3XFkI8MpygtRpzXrIlmWUBclP5A== "@types/prop-types@*": version "15.7.13" @@ -2604,7 +2619,7 @@ resolved "https://registry.npmjs.org/@types/react-native-dotenv/-/react-native-dotenv-0.2.2.tgz" integrity sha512-YDgO2hdTK5PaxZrIFtVXrjeFOhJ+7A9a8VDUK4QmHCPGIB5i6DroLG9IpItX5qCshz7aPsQfgy9X3w82Otd4HA== -"@types/react-native@^0.73.0": +"@types/react-native@*", "@types/react-native@^0.73.0": version "0.73.0" resolved "https://registry.npmjs.org/@types/react-native/-/react-native-0.73.0.tgz" integrity sha512-6ZRPQrYM72qYKGWidEttRe6M5DZBEV5F+MHMHqd4TTYx0tfkcdrUFGdef6CCxY0jXU7wldvd/zA/b0A/kTeJmA== @@ -2660,62 +2675,62 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@8.15.0": - version "8.15.0" - resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.15.0.tgz" - integrity sha512-+zkm9AR1Ds9uLWN3fkoeXgFppaQ+uEVtfOV62dDmsy9QCNqlRHWNEck4yarvRNrvRcHQLGfqBNui3cimoz8XAg== +"@typescript-eslint/eslint-plugin@8.16.0": + version "8.16.0" + resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.16.0.tgz" + integrity sha512-5YTHKV8MYlyMI6BaEG7crQ9BhSc8RxzshOReKwZwRWN0+XvvTOm+L/UYLCYxFpfwYuAAqhxiq4yae0CMFwbL7Q== dependencies: "@eslint-community/regexpp" "^4.10.0" - "@typescript-eslint/scope-manager" "8.15.0" - "@typescript-eslint/type-utils" "8.15.0" - "@typescript-eslint/utils" "8.15.0" - "@typescript-eslint/visitor-keys" "8.15.0" + "@typescript-eslint/scope-manager" "8.16.0" + "@typescript-eslint/type-utils" "8.16.0" + "@typescript-eslint/utils" "8.16.0" + "@typescript-eslint/visitor-keys" "8.16.0" graphemer "^1.4.0" ignore "^5.3.1" natural-compare "^1.4.0" ts-api-utils "^1.3.0" -"@typescript-eslint/parser@^8.0.0 || ^8.0.0-alpha.0", "@typescript-eslint/parser@8.15.0": - version "8.15.0" - resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.15.0.tgz" - integrity sha512-7n59qFpghG4uazrF9qtGKBZXn7Oz4sOMm8dwNWDQY96Xlm2oX67eipqcblDj+oY1lLCbf1oltMZFpUso66Kl1A== +"@typescript-eslint/parser@^8.0.0 || ^8.0.0-alpha.0", "@typescript-eslint/parser@8.16.0": + version "8.16.0" + resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.16.0.tgz" + integrity sha512-D7DbgGFtsqIPIFMPJwCad9Gfi/hC0PWErRRHFnaCWoEDYi5tQUDiJCTmGUbBiLzjqAck4KcXt9Ayj0CNlIrF+w== dependencies: - "@typescript-eslint/scope-manager" "8.15.0" - "@typescript-eslint/types" "8.15.0" - "@typescript-eslint/typescript-estree" "8.15.0" - "@typescript-eslint/visitor-keys" "8.15.0" + "@typescript-eslint/scope-manager" "8.16.0" + "@typescript-eslint/types" "8.16.0" + "@typescript-eslint/typescript-estree" "8.16.0" + "@typescript-eslint/visitor-keys" "8.16.0" debug "^4.3.4" -"@typescript-eslint/scope-manager@8.15.0": - version "8.15.0" - resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.15.0.tgz" - integrity sha512-QRGy8ADi4J7ii95xz4UoiymmmMd/zuy9azCaamnZ3FM8T5fZcex8UfJcjkiEZjJSztKfEBe3dZ5T/5RHAmw2mA== +"@typescript-eslint/scope-manager@8.16.0": + version "8.16.0" + resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.16.0.tgz" + integrity sha512-mwsZWubQvBki2t5565uxF0EYvG+FwdFb8bMtDuGQLdCCnGPrDEDvm1gtfynuKlnpzeBRqdFCkMf9jg1fnAK8sg== dependencies: - "@typescript-eslint/types" "8.15.0" - "@typescript-eslint/visitor-keys" "8.15.0" + "@typescript-eslint/types" "8.16.0" + "@typescript-eslint/visitor-keys" "8.16.0" -"@typescript-eslint/type-utils@8.15.0": - version "8.15.0" - resolved "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.15.0.tgz" - integrity sha512-UU6uwXDoI3JGSXmcdnP5d8Fffa2KayOhUUqr/AiBnG1Gl7+7ut/oyagVeSkh7bxQ0zSXV9ptRh/4N15nkCqnpw== +"@typescript-eslint/type-utils@8.16.0": + version "8.16.0" + resolved "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.16.0.tgz" + integrity sha512-IqZHGG+g1XCWX9NyqnI/0CX5LL8/18awQqmkZSl2ynn8F76j579dByc0jhfVSnSnhf7zv76mKBQv9HQFKvDCgg== dependencies: - "@typescript-eslint/typescript-estree" "8.15.0" - "@typescript-eslint/utils" "8.15.0" + "@typescript-eslint/typescript-estree" "8.16.0" + "@typescript-eslint/utils" "8.16.0" debug "^4.3.4" ts-api-utils "^1.3.0" -"@typescript-eslint/types@8.15.0": - version "8.15.0" - resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.15.0.tgz" - integrity sha512-n3Gt8Y/KyJNe0S3yDCD2RVKrHBC4gTUcLTebVBXacPy091E6tNspFLKRXlk3hwT4G55nfr1n2AdFqi/XMxzmPQ== +"@typescript-eslint/types@8.16.0": + version "8.16.0" + resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.16.0.tgz" + integrity sha512-NzrHj6thBAOSE4d9bsuRNMvk+BvaQvmY4dDglgkgGC0EW/tB3Kelnp3tAKH87GEwzoxgeQn9fNGRyFJM/xd+GQ== -"@typescript-eslint/typescript-estree@8.15.0": - version "8.15.0" - resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.15.0.tgz" - integrity sha512-1eMp2JgNec/niZsR7ioFBlsh/Fk0oJbhaqO0jRyQBMgkz7RrFfkqF9lYYmBoGBaSiLnu8TAPQTwoTUiSTUW9dg== +"@typescript-eslint/typescript-estree@8.16.0": + version "8.16.0" + resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.16.0.tgz" + integrity sha512-E2+9IzzXMc1iaBy9zmo+UYvluE3TW7bCGWSF41hVWUE01o8nzr1rvOQYSxelxr6StUvRcTMe633eY8mXASMaNw== dependencies: - "@typescript-eslint/types" "8.15.0" - "@typescript-eslint/visitor-keys" "8.15.0" + "@typescript-eslint/types" "8.16.0" + "@typescript-eslint/visitor-keys" "8.16.0" debug "^4.3.4" fast-glob "^3.3.2" is-glob "^4.0.3" @@ -2723,22 +2738,22 @@ semver "^7.6.0" ts-api-utils "^1.3.0" -"@typescript-eslint/utils@8.15.0": - version "8.15.0" - resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.15.0.tgz" - integrity sha512-k82RI9yGhr0QM3Dnq+egEpz9qB6Un+WLYhmoNcvl8ltMEededhh7otBVVIDDsEEttauwdY/hQoSsOv13lxrFzQ== +"@typescript-eslint/utils@8.16.0": + version "8.16.0" + resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.16.0.tgz" + integrity sha512-C1zRy/mOL8Pj157GiX4kaw7iyRLKfJXBR3L82hk5kS/GyHcOFmy4YUq/zfZti72I9wnuQtA/+xzft4wCC8PJdA== dependencies: "@eslint-community/eslint-utils" "^4.4.0" - "@typescript-eslint/scope-manager" "8.15.0" - "@typescript-eslint/types" "8.15.0" - "@typescript-eslint/typescript-estree" "8.15.0" + "@typescript-eslint/scope-manager" "8.16.0" + "@typescript-eslint/types" "8.16.0" + "@typescript-eslint/typescript-estree" "8.16.0" -"@typescript-eslint/visitor-keys@8.15.0": - version "8.15.0" - resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.15.0.tgz" - integrity sha512-h8vYOulWec9LhpwfAdZf2bjr8xIp0KNKnpgqSz0qqYYKAW/QZKw3ktRndbiAtUz4acH4QLQavwZBYCc0wulA/Q== +"@typescript-eslint/visitor-keys@8.16.0": + version "8.16.0" + resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.16.0.tgz" + integrity sha512-pq19gbaMOmFE3CbL0ZB8J8BFCo2ckfHBfaIsaOZgBIF4EoISJIdLX5xRhd0FGB0LlHReNRuzoJoMGpTjq8F2CQ== dependencies: - "@typescript-eslint/types" "8.15.0" + "@typescript-eslint/types" "8.16.0" eslint-visitor-keys "^4.2.0" "@urql/core@^5.0.0", "@urql/core@^5.0.6": @@ -3200,9 +3215,9 @@ available-typed-arrays@^1.0.7: possible-typed-array-names "^1.0.0" axios@^1.7.4: - version "1.7.7" - resolved "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz" - integrity sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q== + version "1.7.8" + resolved "https://registry.npmjs.org/axios/-/axios-1.7.8.tgz" + integrity sha512-Uu0wb7KNqK2t5K+YQyVCLM76prD5sRFjKHbJYCP1J7JFGEQ6nN7HWn9+04LAeiJ3ji54lgS/gZCH1oxyrf1SPw== dependencies: follow-redirects "^1.15.6" form-data "^4.0.0" @@ -3570,9 +3585,9 @@ camelize@^1.0.0: integrity sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ== caniuse-lite@^1.0.30001669: - version "1.0.30001684" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001684.tgz" - integrity sha512-G1LRwLIQjBQoyq0ZJGqGIJUXzJ8irpbjHLpVRXDvBEScFJ9b17sgK6vlx0GAJFE21okD7zXl08rRRUfq6HdoEQ== + version "1.0.30001685" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001685.tgz" + integrity sha512-e/kJN1EMyHQzgcMEEgoo+YTCO1NGCmIYHk5Qk8jT6AazWemS5QFKJ5ShCJlH3GZrNIdZofcNCEwZqbMjjKzmnA== chalk@^2.0.1: version "2.4.2" @@ -3686,11 +3701,11 @@ cjs-module-lexer@^1.0.0: integrity sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA== class-variance-authority@^0.7.0: - version "0.7.0" - resolved "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.0.tgz" - integrity sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A== + version "0.7.1" + resolved "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz" + integrity sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg== dependencies: - clsx "2.0.0" + clsx "^2.1.1" clean-stack@^2.0.0: version "2.2.0" @@ -3739,10 +3754,10 @@ clone@^1.0.2: resolved "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz" integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg== -clsx@2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz" - integrity sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q== +clsx@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz" + integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA== co@^4.6.0: version "4.6.0" @@ -4265,9 +4280,9 @@ ejs@^3.1.10: jake "^10.8.5" electron-to-chromium@^1.5.41: - version "1.5.64" - resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.64.tgz" - integrity sha512-IXEuxU+5ClW2IGEYFC2T7szbyVgehupCWQe5GNh+H065CD6U6IFN0s4KeAMFGNmQolRU4IV7zGBWSYMmZ8uuqQ== + version "1.5.67" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.67.tgz" + integrity sha512-nz88NNBsD7kQSAGGJyp8hS6xSPtWwqNogA0mjtc2nUYeEf3nURK9qpV18TuBdDmEDgVWotS8Wkzf+V52dSQ/LQ== emittery@^0.13.1: version "0.13.1" @@ -4452,13 +4467,13 @@ es-shim-unscopables@^1.0.0, es-shim-unscopables@^1.0.2: hasown "^2.0.0" es-to-primitive@^1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz" - integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + version "1.3.0" + resolved "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz" + integrity sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g== dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" + is-callable "^1.2.7" + is-date-object "^1.0.5" + is-symbol "^1.0.4" escalade@^3.1.1, escalade@^3.2.0: version "3.2.0" @@ -4557,16 +4572,16 @@ eslint-visitor-keys@^4.2.0: integrity sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw== "eslint@^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7", "eslint@^6.0.0 || ^7.0.0 || >=8.0.0", "eslint@^8.57.0 || ^9.0.0", eslint@^9.9.0, eslint@>=7.0.0: - version "9.15.0" - resolved "https://registry.npmjs.org/eslint/-/eslint-9.15.0.tgz" - integrity sha512-7CrWySmIibCgT1Os28lUU6upBshZ+GxybLOrmRzi08kS8MBuO8QA7pXEgYgY5W8vK3e74xv0lpjo9DbaGU9Rkw== + version "9.16.0" + resolved "https://registry.npmjs.org/eslint/-/eslint-9.16.0.tgz" + integrity sha512-whp8mSQI4C8VXd+fLgSM0lh3UlmcFtVwUQjyKCFfsp+2ItAIYhlq/hqGahGqHE6cv9unM41VlqKk2VtKYR2TaA== dependencies: "@eslint-community/eslint-utils" "^4.2.0" "@eslint-community/regexpp" "^4.12.1" "@eslint/config-array" "^0.19.0" "@eslint/core" "^0.9.0" "@eslint/eslintrc" "^3.2.0" - "@eslint/js" "9.15.0" + "@eslint/js" "9.16.0" "@eslint/plugin-kit" "^0.2.3" "@humanfs/node" "^0.16.6" "@humanwhocodes/module-importer" "^1.0.1" @@ -4980,9 +4995,9 @@ flow-enums-runtime@^0.0.6: integrity sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw== flow-parser@0.*: - version "0.254.2" - resolved "https://registry.npmjs.org/flow-parser/-/flow-parser-0.254.2.tgz" - integrity sha512-18xCQaVdKNCY0TAEhwUdk1HmRdgsPSraWwu0Zifqo5M4Ubi9LjWTAdlfBFb07Os+fQ9TmzxlyZN6OxK0m9xrBw== + version "0.255.0" + resolved "https://registry.npmjs.org/flow-parser/-/flow-parser-0.255.0.tgz" + integrity sha512-7QHV2m2mIMh6yIMaAPOVbyNEW77IARwO69d4DgvfDCjuORiykdMLf7XBjF7Zeov7Cpe1OXJ8sB6/aaCE3xuRBw== follow-redirects@^1.15.6: version "1.15.9" @@ -5115,7 +5130,7 @@ get-caller-file@^2.0.5: resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: +get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: version "1.2.4" resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz" integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== @@ -5247,9 +5262,9 @@ globals@^14.0.0: integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== globals@^15.9.0: - version "15.12.0" - resolved "https://registry.npmjs.org/globals/-/globals-15.12.0.tgz" - integrity sha512-1+gLErljJFhbOVyaetcwJiJ4+eLe45S2E7P5UiZ9xGfeq3ATQf5DOv9G7MH3gGbKQLkzmNh2DxfZwLdw+j6oTQ== + version "15.13.0" + resolved "https://registry.npmjs.org/globals/-/globals-15.13.0.tgz" + integrity sha512-49TewVEz0UxZjr1WYYsWpPrhyC/B/pA8Bq0fUmet2n+eR7yn0IvNzNaoBwnK6mdkzcN+se7Ez9zUgULTz2QH4g== globalthis@^1.0.4: version "1.0.4" @@ -5271,12 +5286,12 @@ globby@^11.0.1: merge2 "^1.4.1" slash "^3.0.0" -gopd@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz" - integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== +gopd@^1.0.1, gopd@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/gopd/-/gopd-1.1.0.tgz" + integrity sha512-FQoVQnqcdk4hVM4JN1eromaun4iuS34oStkdlLENLdpULsuQcTyXj8w7ayhuUfPwEYZ1ZOooOTT6fdA9Vmx/RA== dependencies: - get-intrinsic "^1.1.3" + get-intrinsic "^1.2.4" got@^11.5.1: version "11.8.6" @@ -5328,9 +5343,11 @@ has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2: es-define-property "^1.0.0" has-proto@^1.0.1, has-proto@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz" - integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== + version "1.1.0" + resolved "https://registry.npmjs.org/has-proto/-/has-proto-1.1.0.tgz" + integrity sha512-QLdzI9IIO1Jg7f9GT1gXpPpXArAn6cS31R1eEZqz08Gc+uQ8/XiqHWt17Fiw+2p6oTTIq5GXEpQkAlA88YRl/Q== + dependencies: + call-bind "^1.0.7" has-symbols@^1.0.2, has-symbols@^1.0.3: version "1.0.3" @@ -5609,19 +5626,19 @@ is-binary-path@~2.1.0: binary-extensions "^2.0.0" is-boolean-object@^1.1.0: - version "1.1.2" - resolved "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz" - integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== + version "1.2.0" + resolved "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.0.tgz" + integrity sha512-kR5g0+dXf/+kXnqI+lu0URKYPKgICtHGGNCDSB10AaUFj3o/HkB3u7WfpRBJGFopxxY0oH3ux7ZsDjLtK7xqvw== dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" + call-bind "^1.0.7" + has-tostringtag "^1.0.2" is-buffer@~1.1.6: version "1.1.6" resolved "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== -is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: +is-callable@^1.1.3, is-callable@^1.2.7: version "1.2.7" resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz" integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== @@ -5640,7 +5657,7 @@ is-data-view@^1.0.1: dependencies: is-typed-array "^1.1.13" -is-date-object@^1.0.1, is-date-object@^1.0.5: +is-date-object@^1.0.5: version "1.0.5" resolved "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz" integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== @@ -5704,11 +5721,12 @@ is-negative-zero@^2.0.3: integrity sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw== is-number-object@^1.0.4: - version "1.0.7" - resolved "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz" - integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== + version "1.1.0" + resolved "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.0.tgz" + integrity sha512-KVSZV0Dunv9DTPkhXwcZ3Q+tUc9TsaE1ZwX5J2WMvsSGS6Md8TFPun5uwh0yRdrNerI6vf/tbJxqSx4c1ZI1Lw== dependencies: - has-tostringtag "^1.0.0" + call-bind "^1.0.7" + has-tostringtag "^1.0.2" is-number@^7.0.0: version "7.0.0" @@ -5743,12 +5761,14 @@ is-potential-custom-element-name@^1.0.1: integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== is-regex@^1.1.4: - version "1.1.4" - resolved "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz" - integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== + version "1.2.0" + resolved "https://registry.npmjs.org/is-regex/-/is-regex-1.2.0.tgz" + integrity sha512-B6ohK4ZmoftlUe+uvenXSbPJFo6U37BH7oO1B3nQH8f/7h27N56s85MhUtbFJAziz5dcmuR3i8ovUl35zp8pFA== dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" + call-bind "^1.0.7" + gopd "^1.1.0" + has-tostringtag "^1.0.2" + hasown "^2.0.2" is-set@^2.0.3: version "2.0.3" @@ -5773,13 +5793,14 @@ is-stream@^2.0.0: integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== is-string@^1.0.5, is-string@^1.0.7: - version "1.0.7" - resolved "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz" - integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== + version "1.1.0" + resolved "https://registry.npmjs.org/is-string/-/is-string-1.1.0.tgz" + integrity sha512-PlfzajuF9vSo5wErv3MJAKD/nqf9ngAs1NFQYm16nUYFO2IzxJ2hcm+IOCg+EEopdykNNUhVq5cz35cAUxU8+g== dependencies: - has-tostringtag "^1.0.0" + call-bind "^1.0.7" + has-tostringtag "^1.0.2" -is-symbol@^1.0.2, is-symbol@^1.0.3: +is-symbol@^1.0.3, is-symbol@^1.0.4: version "1.0.4" resolved "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz" integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== @@ -7113,10 +7134,10 @@ mz@^2.7.0: object-assign "^4.0.1" thenify-all "^1.0.0" -nanoid@^3.1.23, nanoid@^3.3.7: - version "3.3.7" - resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz" - integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== +nanoid@^3.1.23, nanoid@^3.3.1, nanoid@^3.3.7: + version "3.3.8" + resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz" + integrity sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w== nativewind@^2.0.11: version "2.0.11" @@ -7246,9 +7267,9 @@ nvm@^0.0.4: integrity sha512-jvmyELykYcdyd0VCGY0E8Aqe5MngEasVvlPvrcJHbwBMUbVqa72mPdQuPzyTcykEtEx7jDrMY0QA5MoV+8EhgA== nwsapi@^2.2.2: - version "2.2.13" - resolved "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.13.tgz" - integrity sha512-cTGB9ptp9dY9A5VbMSe7fQBcl/tt22Vcqdq8+eN93rblOuE0aCFu4aZ2vMwct/2t+lFnosm8RkQW1I0Omb1UtQ== + version "2.2.16" + resolved "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.16.tgz" + integrity sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ== ob1@0.81.0: version "0.81.0" @@ -7802,9 +7823,9 @@ proxy-from-env@^1.1.0: integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== psl@^1.1.33: - version "1.13.0" - resolved "https://registry.npmjs.org/psl/-/psl-1.13.0.tgz" - integrity sha512-BFwmFXiJoFqlUpZ5Qssolv15DMyc84gTBds1BjsV1BfXEo1UyyD7GsmN67n7J77uRhoSNW1AXtXKPLcBFQn9Aw== + version "1.15.0" + resolved "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz" + integrity sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w== dependencies: punycode "^2.3.1" @@ -7948,7 +7969,7 @@ react-native-dotenv@^3.4.11: dependencies: dotenv "^16.4.5" -react-native-gesture-handler@>=2.0.0, react-native-gesture-handler@>=2.x.x, react-native-gesture-handler@~2.20.2: +react-native-gesture-handler@>=2.0.0, react-native-gesture-handler@>=2.16.1, react-native-gesture-handler@>=2.x.x, react-native-gesture-handler@~2.20.2: version "2.20.2" resolved "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.20.2.tgz" integrity sha512-HqzFpFczV4qCnwKlvSAvpzEXisL+Z9fsR08YV5LfJDkzuArMhBu2sOoSPUF/K62PCoAb+ObGlTC83TKHfUd0vg== @@ -7987,10 +8008,10 @@ react-native-reanimated-carousel@^3.5.1: resolved "https://registry.npmjs.org/react-native-reanimated-carousel/-/react-native-reanimated-carousel-3.5.1.tgz" integrity sha512-9BBQV6JAYSQm2lV7MFtT4mzapXmW4IZO6s38gfiJL84Jg23ivGB1UykcNQauKgtHyhtW2NuZJzItb1s42lM+hA== -react-native-reanimated@>=2.x.x, react-native-reanimated@>=3.0.0, react-native-reanimated@~3.16.1: - version "3.16.2" - resolved "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.16.2.tgz" - integrity sha512-Jk8y+iOLcK3J8YK3Qj/U+zclwfetgM1fFhlYaxFrJ5TPvuwdRG5YY1pvO91FcZ3C1+0meGHR6BZGl9d/Z0xh3Q== +react-native-reanimated@>=2.x.x, react-native-reanimated@>=3.0.0, react-native-reanimated@>=3.16.0, react-native-reanimated@~3.16.1: + version "3.16.3" + resolved "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.16.3.tgz" + integrity sha512-OWlA6e1oHhytTpc7WiSZ7Tmb8OYwLKYZz29Sz6d6WAg60Hm5GuAiKIWUG7Ako7FLcYhFkA0pEQ2xPMEYUo9vlw== dependencies: "@babel/plugin-transform-arrow-functions" "^7.0.0-0" "@babel/plugin-transform-class-properties" "^7.0.0-0" @@ -8615,9 +8636,9 @@ shebang-regex@^3.0.0: integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== shell-quote@^1.6.1: - version "1.8.1" - resolved "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz" - integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA== + version "1.8.2" + resolved "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz" + integrity sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA== side-channel@^1.0.4, side-channel@^1.0.6: version "1.0.6" @@ -9220,9 +9241,9 @@ tr46@~0.0.3: integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== ts-api-utils@^1.3.0: - version "1.4.1" - resolved "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.1.tgz" - integrity sha512-5RU2/lxTA3YUZxju61HO2U6EoZLvBLtmV2mbTvqyu4a/7s7RmJPT+1YekhMVsQhznRWk/czIwDUg+V8Q9ZuG4w== + version "1.4.3" + resolved "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz" + integrity sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw== ts-interface-checker@^0.1.9: version "0.1.13" @@ -9322,13 +9343,13 @@ typed-array-length@^1.0.6: reflect.getprototypeof "^1.0.6" typescript-eslint@^8.1.0: - version "8.15.0" - resolved "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.15.0.tgz" - integrity sha512-wY4FRGl0ZI+ZU4Jo/yjdBu0lVTSML58pu6PgGtJmCufvzfV565pUF6iACQt092uFOd49iLOTX/sEVmHtbSrS+w== + version "8.16.0" + resolved "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.16.0.tgz" + integrity sha512-wDkVmlY6O2do4V+lZd0GtRfbtXbeD0q9WygwXXSJnC1xorE8eqyC2L1tJimqpSeFrOzRlYtWnUp/uzgHQOgfBQ== dependencies: - "@typescript-eslint/eslint-plugin" "8.15.0" - "@typescript-eslint/parser" "8.15.0" - "@typescript-eslint/utils" "8.15.0" + "@typescript-eslint/eslint-plugin" "8.16.0" + "@typescript-eslint/parser" "8.16.0" + "@typescript-eslint/utils" "8.16.0" typescript@>=4.2.0, "typescript@>=4.3 <6", typescript@~5.3.3: version "5.3.3" @@ -9350,10 +9371,10 @@ unbox-primitive@^1.0.2: has-symbols "^1.0.3" which-boxed-primitive "^1.0.2" -undici-types@~6.19.8: - version "6.19.8" - resolved "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz" - integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== +undici-types@~6.20.0: + version "6.20.0" + resolved "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz" + integrity sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg== undici@^6.18.2: version "6.21.0" @@ -9692,9 +9713,9 @@ which-collection@^1.0.2: is-weakset "^2.0.3" which-typed-array@^1.1.14, which-typed-array@^1.1.15: - version "1.1.15" - resolved "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz" - integrity sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA== + version "1.1.16" + resolved "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.16.tgz" + integrity sha512-g+N+GAWiRj66DngFwHvISJd+ITsyphZvD1vChfVg6cEdnzy53GzB3oy0fUNlvhz7H7+MiqhYr26qxQShCpKTTQ== dependencies: available-typed-arrays "^1.0.7" call-bind "^1.0.7" @@ -9802,7 +9823,7 @@ ws@^8.12.1: resolved "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz" integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== -ws@^8.14.2: +ws@^8.18.0: version "8.18.0" resolved "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz" integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== From 96a328453f4497a775bdc496ccc8debefe07c436 Mon Sep 17 00:00:00 2001 From: gus-s-42 <156837430+gus-s-42@users.noreply.github.com> Date: Mon, 2 Dec 2024 19:21:02 -0500 Subject: [PATCH 2/3] Scrum 33 profile screen (#73) Co-authored-by: rmsap <87085375+rmsap@users.noreply.github.com> Co-authored-by: Ryan Saperstein --- frontend/assets/images/key-icon.png | Bin 0 -> 641 bytes frontend/assets/images/left-arrow.png | Bin 0 -> 334 bytes frontend/assets/images/link-icon.png | Bin 0 -> 492 bytes frontend/src/components/Divider.tsx | 2 +- frontend/src/navigation/ProfileNavigator.tsx | 35 +- .../src/screens/profile/ProfileEditScreen.tsx | 95 + .../profile/ProfileLegalDocumentsScreen.tsx | 54 + .../src/screens/profile/ProfileScreen.tsx | 150 +- .../screens/profile/ProfileSettingsScreen.tsx | 92 + .../components/PageHeaderNavigation.tsx | 32 + .../components/ProfilePageNavigator.tsx | 19 +- frontend/src/types/investor.ts | 9 + frontend/yarn.lock | 3597 ++++++++--------- 13 files changed, 2071 insertions(+), 2014 deletions(-) create mode 100644 frontend/assets/images/key-icon.png create mode 100644 frontend/assets/images/left-arrow.png create mode 100644 frontend/assets/images/link-icon.png create mode 100644 frontend/src/screens/profile/ProfileEditScreen.tsx create mode 100644 frontend/src/screens/profile/ProfileLegalDocumentsScreen.tsx create mode 100644 frontend/src/screens/profile/ProfileSettingsScreen.tsx create mode 100644 frontend/src/screens/profile/components/PageHeaderNavigation.tsx diff --git a/frontend/assets/images/key-icon.png b/frontend/assets/images/key-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..b94998643625761f97bdce735c5d351f183f715a GIT binary patch literal 641 zcmeAS@N?(olHy`uVBq!ia0vp^h9Jzr1|*B;ILZJi#^NA%Cx&(BWL`2bFe!SvIEG}f zzKwWWc*uY!wWaTX{-d0O9DT*^bN*$TXP7tezF;e9?mNKIGeJ;d;o1$neH&AFraW2q zsIObMe(!gklYVN#|28tMVbDInwE;#MvMvj<<6Ilp8YaCkRDH{@w)&f^YA=RZCr|%; z<3`|(x`TR*YnbO%lr35t@5U(Oz@fW5>}m5W&JT(6dEeYykkZib-fSidUyDP-!Hzr4 z2Rci(%BGmNth4i1@L{+gq%ZaLUx1R+X-nQ6x18jktCd|>$d)w@v)Gq$<=)qN4#|a# zDy#l=F-^STSfpc`A2vJG^o-HEI>C+>j=Xi+^V#)hOj?rG9i_DU!bIl1$65r!o8DKt zv1eC!f9rNyE$WnX`Mu}$u4Qe)f8-iAS{5j|2G<@DJAYQM^TvUO)SHaiAznEj4JR?I zcl0=Nmors%F6%n&l(y4BHt!^l_#U_ybYAS_$&hL+n*WuM~R7#xr6{P&+k6AR`vu44w+NJdsOK*98Sat=`Lo!(3 z&bY{V*nr0+zoqZO*$Rnx$xl?o z<3P^zCk-+MLKj4em`eELuQhJdw|e!DMc~`QJ*Cn+7jwxSO?@|ETMI|juiabaCU)1H ze|co9#5FhW--6Q=H7B&FG@31+sGJt!Df`qzD5F@)GRbY~mBLE*b)E``FXdPUy^`2G z@kQ$tn}9s0isdsl$j`RhFwYh0R;LHt;bN@Ee|JvU1oSyyYJ_K+uP=iZkj(+aAaE&o PGKlhY^>bP0l+XkKJsEqg literal 0 HcmV?d00001 diff --git a/frontend/assets/images/link-icon.png b/frontend/assets/images/link-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..d50b381bc2c7fdf89bd91fd0a018ac7ff0884887 GIT binary patch literal 492 zcmVPx$j7da6R9Fekn1M~hFc3xm2#mle9f1vC6gDXvzy^%M2#f%FR#PRXPa2;uDJNB_ zf9?Cv7pHL|{quN~^eO3E(og5-OVYEMA6ieoMIL~920LiR$H2t(UDK|4-V=jkVgO=f zC))BvgWfjgFOle?WvXSN-XuL3lPZa|wl;AK#TwfyZUF(?B2rI!^>GW(p-_JTu@-Gn ztXNp4H6U!PzZHw1ZUG$*wFT%86co+ zR6vyiK{*Ol4m1k23(yEu6%ct?kv0bu>Dcma-wYM^1L zCo?N1Uy#}ZXpkXKy0CJXeGL_6qvHC5K6|)YBan|38 ziR9TK*58U*hr~GRZ^cCN>=5f8#XX;nBRCJf(ZBVHB3IX*PstM)lgBIix8LV`TF0000jK;M9 literal 0 HcmV?d00001 diff --git a/frontend/src/components/Divider.tsx b/frontend/src/components/Divider.tsx index c0021ec..92290f1 100644 --- a/frontend/src/components/Divider.tsx +++ b/frontend/src/components/Divider.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { View, Image, ImageSourcePropType } from 'react-native'; import { styled } from 'nativewind'; -import { CaptionText } from './typography'; +import { CaptionText } from '../components/typography'; const StyledView = styled(View); const StyledImage = styled(Image); diff --git a/frontend/src/navigation/ProfileNavigator.tsx b/frontend/src/navigation/ProfileNavigator.tsx index 0935924..dedc618 100644 --- a/frontend/src/navigation/ProfileNavigator.tsx +++ b/frontend/src/navigation/ProfileNavigator.tsx @@ -2,6 +2,9 @@ import React from 'react'; import { createNativeStackNavigator } from '@react-navigation/native-stack'; import ProfileScreen from '../screens/profile/ProfileScreen'; +import ProfileLegalDocumentsScreen from '../screens/profile/ProfileLegalDocumentsScreen'; +import ProfileSettingsScreen from '../screens/profile/ProfileSettingsScreen'; +import ProfileEditScreen from '../screens/profile/ProfileEditScreen'; const Stack = createNativeStackNavigator(); @@ -11,7 +14,37 @@ export default function ProfileNavigator() { + + + ); diff --git a/frontend/src/screens/profile/ProfileEditScreen.tsx b/frontend/src/screens/profile/ProfileEditScreen.tsx new file mode 100644 index 0000000..f6a7e36 --- /dev/null +++ b/frontend/src/screens/profile/ProfileEditScreen.tsx @@ -0,0 +1,95 @@ +import React from 'react'; +import { Image, Text, View, TouchableOpacity } from 'react-native'; +import { styled } from 'nativewind'; +import ProfilePageNavigator from './components/ProfilePageNavigator'; +import { NavigationScreenProp } from 'react-navigation'; + +import Divider from '../../components/Divider'; +import Button from '../../components/Button'; +import { BodyText, SubheadingText } from '../../components/typography'; +import { useInvestorProfile } from '../../services/investor'; +import ProfiileHeaderNavigation from './components/PageHeaderNavigation'; +import PageHeaderNavigation from './components/PageHeaderNavigation'; + +const StyledView = styled(View); +const StyledText = styled(Text); +const StyledImage = styled(Image); + +interface ProfileLegalDocumentsScreenProps { + // This actually should be `any`, so disabling the linter rule + // eslint-disable-next-line @typescript-eslint/no-explicit-any + navigation: NavigationScreenProp; +} + +const ProfileInfo = () => { + const { profile, isLoading } = useInvestorProfile(); + if(isLoading) { + return loading... + } + if(!profile) { + return no profile found! + } + return ( + + + + + + Contact Details + + + + Name + {profile.first} {profile.last} + + + + + + Email + {profile.email} + + + + + + Mobile + {profile.phone_number} + + + + + + Mailing Address + {profile.premise} {profile.street} + + + + + + Social Security + *** **** ***** + + + + ); +}; + +export default function ProfileEditScreen({ navigation }: ProfileLegalDocumentsScreenProps) { + return( + + + + + + + + + + + + + + + ); +} \ No newline at end of file diff --git a/frontend/src/screens/profile/ProfileLegalDocumentsScreen.tsx b/frontend/src/screens/profile/ProfileLegalDocumentsScreen.tsx new file mode 100644 index 0000000..9df6363 --- /dev/null +++ b/frontend/src/screens/profile/ProfileLegalDocumentsScreen.tsx @@ -0,0 +1,54 @@ +import React from 'react'; +import { Image, Text, View, TouchableOpacity } from 'react-native'; +import { styled } from 'nativewind'; +import ProfilePageNavigator from './components/ProfilePageNavigator'; +import { NavigationScreenProp } from 'react-navigation'; + +import Divider from '../../components/Divider'; +import PageHeaderNavigation from './components/PageHeaderNavigation'; + +const StyledView = styled(View); +const StyledText = styled(Text); +const StyledImage = styled(Image); + +interface ProfileLegalDocumentsScreenProps { + // This actually should be `any`, so disabling the linter rule + // eslint-disable-next-line @typescript-eslint/no-explicit-any + navigation: NavigationScreenProp; +} + +export default function ProfileLegalDocumentsScreen({ navigation }: ProfileLegalDocumentsScreenProps) { + return( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +} \ No newline at end of file diff --git a/frontend/src/screens/profile/ProfileScreen.tsx b/frontend/src/screens/profile/ProfileScreen.tsx index 6fe715f..a9b49dd 100644 --- a/frontend/src/screens/profile/ProfileScreen.tsx +++ b/frontend/src/screens/profile/ProfileScreen.tsx @@ -3,8 +3,11 @@ import { Image, Text, View, TouchableOpacity } from 'react-native'; import { styled } from 'nativewind'; import ProfilePageNavigator from './components/ProfilePageNavigator'; import { NavigationScreenProp } from 'react-navigation'; -import NotificationButton from './components/NotificationButton'; +import { useInvestorProfile } from '../../../src/services/investor'; + import Button from '../../components/Button'; +import Divider from '../../components/Divider'; +import { BodyBoldText, BodyText, HeadingText, SubheadingText } from '../../components/typography'; const StyledView = styled(View); const StyledText = styled(Text); @@ -19,10 +22,10 @@ interface ProfileScreenProps { //Button to navigate to the portfolio page const EditProfileButton = ({ navigation }) => { return ( - + - - - - + {/* Forgot Login and Next Button */} + + + + - - + + ); } diff --git a/frontend/src/screens/login/login_flow/LoginPasswordScreen.tsx b/frontend/src/screens/login/login_flow/LoginPasswordScreen.tsx index 9d93b36..250f115 100644 --- a/frontend/src/screens/login/login_flow/LoginPasswordScreen.tsx +++ b/frontend/src/screens/login/login_flow/LoginPasswordScreen.tsx @@ -1,30 +1,31 @@ import React, { useState } from 'react'; -import { View, Text, KeyboardAvoidingView, Platform, ScrollView, TouchableOpacity, TextInput } from 'react-native'; +import { View, Text, KeyboardAvoidingView, Platform, ScrollView, TouchableOpacity, SafeAreaView } from 'react-native'; import { styled } from 'nativewind'; import Button from '../../../components/Button'; import { useAuth } from '../../../context/AuthContext'; // Updated import path for useAuth -import ProgressBarComponent from '../../../components/ProgressBar'; import { Ionicons } from '@expo/vector-icons'; import WelcomeToThreeStonesComponent from '../components/WelcomeToThreeStones'; import TextInputComponent from '../components/TextInputComponent'; +import NavProgressBar from '../components/NavProgressBar'; +import OnboardingScreenWrapper from '../components/OnboardingScreenWrapper'; const StyledView = styled(View); const StyledText = styled(Text); -const StyledKeyboardAvoidingView = styled(KeyboardAvoidingView); -const StyledScrollView = styled(ScrollView); const StyledTouchableOpacity = styled(TouchableOpacity); export default function LoginPasswordScreen({ navigation }) { const { loginData, updateLoginData, login } = useAuth(); // Access loginData and updateLoginData from AuthContext - const [password] = useState(loginData.password); + const [password, setPassword] = useState(loginData.password); const [error, setError] = useState(null); const handleLogin = async () => { try { - await login(loginData.email, password); + console.log('Logging in with:', loginData.email, loginData.password); + await login(loginData.email, loginData.password); setError(null); } catch (error) { setError("Invalid username or password"); + console.log('Error logging in:', error); } }; @@ -33,67 +34,53 @@ export default function LoginPasswordScreen({ navigation }) { }; return ( - - - + + navigation.goBack()} /> - {/* Progress Bar */} - - - + {/* Welcome Text */} + - {/* Welcome Text */} - + {/* Email Display with Edit Icon */} + + {loginData.email} + + + + - {/* Email Display with Edit Icon */} - - {loginData.email} - - - - + {/* Password Input Section */} + + { updateLoginData('password', input); }} + isPassword={true} + error={!!error} + /> + {error && ( + + {error} + + )} + - {/* Password Input Section */} - - updateLoginData('password', input)} - isPassword={true} - error= {!!error} - /> - {error && ( - - {error} - - )} - - - {/* Continue Button */} - - - - - - - + {/* Continue Button */} + + + + + ); } \ No newline at end of file diff --git a/frontend/src/screens/login/signup_flow/ConnectAccountsScreen.tsx b/frontend/src/screens/login/signup_flow/ConnectAccountsScreen.tsx index 257489f..e4da354 100644 --- a/frontend/src/screens/login/signup_flow/ConnectAccountsScreen.tsx +++ b/frontend/src/screens/login/signup_flow/ConnectAccountsScreen.tsx @@ -1,53 +1,42 @@ import React from 'react'; -import { View, Text, KeyboardAvoidingView, Platform, ScrollView } from 'react-native'; +import { View, Text} from 'react-native'; import { styled } from 'nativewind'; import Button from '../../../components/Button'; -import ProgressBar from '../../../components/ProgressBar'; +import NavProgressBar from '../components/NavProgressBar'; +import OnboardingScreenWrapper from '../components/OnboardingScreenWrapper'; const StyledView = styled(View); const StyledText = styled(Text); -const StyledKeyboardAvoidingView = styled(KeyboardAvoidingView); -const StyledScrollView = styled(ScrollView); export default function ConnectAccountsScreen({ navigation }) { return ( - - - - {/* Progress Bar */} - - - + + {/* Progress Bar */} + navigation.goBack()} /> - {/* Connect Accounts Section */} - - Connect Accounts - - Connect your bank accounts to proceed. (Plaid integration coming soon) - - {/* Placeholder for Plaid integration */} - - [Plaid Integration Here] - - + {/* Connect Accounts Section */} + + Connect Accounts + + Connect your bank accounts to proceed. (Plaid integration coming soon) + - {/* Continue Button */} - - - - - - + {/* Placeholder for Plaid integration */} + + [Plaid Integration Here] + + + + {/* Continue Button */} + + + + + ); } diff --git a/frontend/src/screens/login/signup_flow/EmailInputScreen.tsx b/frontend/src/screens/login/signup_flow/EmailInputScreen.tsx index 3633d80..2250ded 100644 --- a/frontend/src/screens/login/signup_flow/EmailInputScreen.tsx +++ b/frontend/src/screens/login/signup_flow/EmailInputScreen.tsx @@ -1,16 +1,14 @@ import React, { useState } from 'react'; -import { View, Text, KeyboardAvoidingView, Platform, ScrollView, TextInput } from 'react-native'; +import { View, Text} from 'react-native'; import { styled } from 'nativewind'; import Button from '../../../components/Button'; -import ProgressBar from '../../../components/ProgressBar'; import TextInputComponent from '../components/TextInputComponent'; import { useAuth } from '../../../context/AuthContext'; +import NavProgressBar from '../components/NavProgressBar'; +import OnboardingScreenWrapper from '../components/OnboardingScreenWrapper'; const StyledView = styled(View); const StyledText = styled(Text); -const StyledKeyboardAvoidingView = styled(KeyboardAvoidingView); -const StyledScrollView = styled(ScrollView); -const StyledTextInput = styled(TextInput); export default function EmailInputScreen({ navigation }) { const { signupData, updateSignupData } = useAuth(); @@ -22,48 +20,36 @@ export default function EmailInputScreen({ navigation }) { }; return ( - - - - {/* Progress Bar */} - - - + - {/* Email Input Section */} - - - Let's start with your email - - - You’ll use this email to log in next time. - - setEmail(text)} - keyboardType='email-address' - > - + {/* Progress Bar */} + navigation.goBack()} /> - {/* Continue Button */} - - - - - - + {/* Email Input Section */} + + Let's start with your email + + You’ll use this email to log in next time. + + setEmail(text)} + keyboardType="email-address" + > + + + + + {/* Continue Button */} + + + + + ); } diff --git a/frontend/src/screens/login/signup_flow/LegalInformationScreen.tsx b/frontend/src/screens/login/signup_flow/LegalInformationScreen.tsx index a9cc9ef..7e9d2b3 100644 --- a/frontend/src/screens/login/signup_flow/LegalInformationScreen.tsx +++ b/frontend/src/screens/login/signup_flow/LegalInformationScreen.tsx @@ -1,18 +1,25 @@ import React, { useState } from 'react'; -import { View, Text, KeyboardAvoidingView, Platform, ScrollView, TouchableOpacity } from 'react-native'; +import { + View, + Text, + TouchableOpacity, + SafeAreaView, + TouchableWithoutFeedback, + Keyboard +} from 'react-native'; import { styled } from 'nativewind'; import { GooglePlacesAutocomplete } from 'react-native-google-places-autocomplete'; import Button from '../../../components/Button'; -import ProgressBar from '../../../components/ProgressBar'; +import NavProgressBar from '../components/NavProgressBar'; import { useAuth } from '../../../context/AuthContext'; import TextInputComponent from '../components/TextInputComponent'; -import Config from 'react-native-config'; +import Constants from 'expo-constants'; +const GOOGLE_API_KEY = Constants.expoConfig.extra.googleApiKey; const StyledView = styled(View); const StyledText = styled(Text); -const StyledKeyboardAvoidingView = styled(KeyboardAvoidingView); -const StyledScrollView = styled(ScrollView); const StyledTouchableOpacity = styled(TouchableOpacity); +const StyledSafeAreaView = styled(SafeAreaView); export default function LegalInformationScreen({ navigation }) { const { signupData, updateSignupData } = useAuth(); // Access signupData and updateSignupData from AuthContext @@ -23,15 +30,19 @@ export default function LegalInformationScreen({ navigation }) { const components = details?.address_components || []; const findComponent = (type) => components.find((c) => c.types.includes(type))?.long_name || ''; + const streetNumber = findComponent('street_number'); + const route = findComponent('route'); + const addressLine = `${streetNumber} ${route}`.trim(); // Combine street number and route + const parsedAddress = { - addressLine: findComponent('route') || findComponent('street_address'), + addressLine, city: findComponent('locality'), zipCode: findComponent('postal_code'), country: findComponent('country'), }; Object.entries(parsedAddress).forEach(([key, value]) => { - updateSignupData(`address.${key}`, value); // Update address in signupData + updateSignupData(`address.${key}`, value); }); }; @@ -40,26 +51,22 @@ export default function LegalInformationScreen({ navigation }) { }; return ( - - + + - {/* Progress Bar */} - - - + navigation.goBack()} + /> {/* Legal Information Input Section */} - Some legal information + + Some legal information + We need this information to get you started investing in 3 Stones. @@ -70,8 +77,8 @@ export default function LegalInformationScreen({ navigation }) { value={signupData.ssn} onChangeText={(input) => updateSignupData('ssn', input)} keyboardType="numeric" - > - + maxLength={9} + /> {/* Address Input */} {!isManualEntry ? ( @@ -80,7 +87,7 @@ export default function LegalInformationScreen({ navigation }) { fetchDetails={true} onPress={handleAddressSelect} query={{ - key: Config.GOOGLE_API_KEY, + key: GOOGLE_API_KEY, language: 'en', }} styles={{ @@ -107,37 +114,41 @@ export default function LegalInformationScreen({ navigation }) { updateSignupData('address.addressLine', input)} - keyboardType='default' - > - + onChangeText={(input) => + updateSignupData('address.addressLine', input) + } + keyboardType="default" + /> updateSignupData('address.city', input)} - keyboardType='default' - > - + keyboardType="default" + /> updateSignupData('address.zipCode', input)} - keyboardType='numeric' - > - + onChangeText={(input) => + updateSignupData('address.zipCode', input) + } + keyboardType="numeric" + /> updateSignupData('address.country', input)} - > - + onChangeText={(input) => + updateSignupData('address.country', input) + } + /> )} {/* Toggle Manual Entry */} setIsManualEntry((prev) => !prev)}> - {isManualEntry ? 'Use Address Autocomplete' : 'Enter Address Manually'} + {isManualEntry + ? 'Use Address Autocomplete' + : 'Enter Address Manually'} @@ -153,7 +164,7 @@ export default function LegalInformationScreen({ navigation }) { - - + + ); } diff --git a/frontend/src/screens/login/signup_flow/PasswordInputScreen.tsx b/frontend/src/screens/login/signup_flow/PasswordInputScreen.tsx index 82062dd..6cfc2cc 100644 --- a/frontend/src/screens/login/signup_flow/PasswordInputScreen.tsx +++ b/frontend/src/screens/login/signup_flow/PasswordInputScreen.tsx @@ -1,15 +1,14 @@ import React, { useState } from 'react'; -import { View, Text, KeyboardAvoidingView, Platform, ScrollView, TextInput } from 'react-native'; +import { View, Text } from 'react-native'; import { styled } from 'nativewind'; import Button from '../../../components/Button'; -import ProgressBar from '../../../components/ProgressBar'; import TextInputComponent from '../components/TextInputComponent'; import { useAuth } from '../../../context/AuthContext'; +import NavProgressBar from '../components/NavProgressBar'; +import OnboardingScreenWrapper from '../components/OnboardingScreenWrapper'; const StyledView = styled(View); const StyledText = styled(Text); -const StyledKeyboardAvoidingView = styled(KeyboardAvoidingView); -const StyledScrollView = styled(ScrollView); export default function PasswordInputScreen({ navigation }) { const { signupData, updateSignupData } = useAuth(); @@ -21,49 +20,35 @@ export default function PasswordInputScreen({ navigation }) { }; return ( - - - - {/* Progress Bar */} - - - + + navigation.goBack()} /> - {/* Password Input Section */} - - - Create a password - - - Choose a strong password for your account. - - setPassword(text)} - isPassword={true} - > - + {/* Password Input Section */} + + Create a password + + Choose a strong password for your account. + - {/* Continue Button */} - - - - - - + setPassword(text)} + isPassword={true} + > + + + + {/* Continue Button */} + + + + + ); } diff --git a/frontend/src/screens/login/signup_flow/QuestionsScreen.tsx b/frontend/src/screens/login/signup_flow/QuestionsScreen.tsx index 2e552fe..e3868af 100644 --- a/frontend/src/screens/login/signup_flow/QuestionsScreen.tsx +++ b/frontend/src/screens/login/signup_flow/QuestionsScreen.tsx @@ -1,15 +1,15 @@ import React, { useState } from 'react'; -import { View, Text, KeyboardAvoidingView, Platform, ScrollView } from 'react-native'; +import { View, Text} from 'react-native'; import { styled } from 'nativewind'; import Button from '../../../components/Button'; -import ProgressBar from '../../../components/ProgressBar'; +import NavProgressBar from '../components/NavProgressBar'; import QuestionCard from '../components/QuestionCard'; import { useAuth } from '../../../context/AuthContext'; // Import AuthContext +import OnboardingScreenWrapper from '../components/OnboardingScreenWrapper'; + const StyledView = styled(View); const StyledText = styled(Text); -const StyledKeyboardAvoidingView = styled(KeyboardAvoidingView); -const StyledScrollView = styled(ScrollView); export default function QuestionsScreen({ navigation }) { const { signupData, updateSignupData, signUp } = useAuth(); // Use AuthContext to manage signup data @@ -50,11 +50,11 @@ export default function QuestionsScreen({ navigation }) { const handleSignup = async () => { try { - await signUp(signupData.email, signupData.password); + await signUp(signupData.email, signupData.password); } catch (error) { console.error('Error signing up:', error.message); } - }; + }; const handleNext = () => { if (currentIndex < questions.length - 1) { @@ -69,48 +69,38 @@ export default function QuestionsScreen({ navigation }) { }; return ( - - - + - {/* Progress Bar */} - - - + {/* Progress Bar */} + navigation.goBack()} />\ - {/* User Details Input Section */} - - Last but not least! - - Take a second to answer questions to better understand you as an investor. - - + {/* User Details Input Section */} + + Last but not least! + + Take a second to answer questions to better understand you as an investor. + + - {/* Question cards */} - + {/* Question cards */} + - {/* Continue Button */} - - - - + {/* Continue Button */} + + + + - - - + ); } diff --git a/frontend/src/screens/login/signup_flow/SignupMainScreen.tsx b/frontend/src/screens/login/signup_flow/SignupMainScreen.tsx index e7f0a25..e1c5d4f 100644 --- a/frontend/src/screens/login/signup_flow/SignupMainScreen.tsx +++ b/frontend/src/screens/login/signup_flow/SignupMainScreen.tsx @@ -1,14 +1,15 @@ import React, { useContext } from 'react'; -import { View, Text, TextInput, TouchableOpacity, ScrollView, KeyboardAvoidingView, Platform } from 'react-native'; +import { View, Text, TouchableOpacity } from 'react-native'; import { styled } from 'nativewind'; import Button from '../../../components/Button'; -import { useAuth } from '../../../context/AuthContext'; // Update import path based on where AuthContext is stored import WelcomeToThreeStonesComponent from '../components/WelcomeToThreeStones'; import Divider from '../../../components/Divider'; +import OnboardingScreenWrapper from '../components/OnboardingScreenWrapper'; +import NavProgressBar from '../components/NavProgressBar'; + const StyledView = styled(View); const StyledText = styled(Text); -const StyledScrollView = styled(ScrollView); const StyledTouchableOpacity = styled(TouchableOpacity); export default function SignUpMainScreen({ navigation }) { @@ -17,34 +18,23 @@ export default function SignUpMainScreen({ navigation }) { }; return ( - - - - {/* Header */} - - - - Providing the tools you need to make your first investments in real estate. - - - {/* Email Input Section */} - - - - - - {/* Google and Apple Sign-In Buttons (Stub) */} - - Sign in with Google - - - Sign in with Apple - - + + navigation.goBack()} /> + + {/* Header */} + + + + Providing the tools you need to make your first investments in real estate. + + + {/* Email Input Section */} + + - + ); } diff --git a/frontend/src/screens/login/signup_flow/UserDetailsScreen.tsx b/frontend/src/screens/login/signup_flow/UserDetailsScreen.tsx index 9703f05..2ef69a7 100644 --- a/frontend/src/screens/login/signup_flow/UserDetailsScreen.tsx +++ b/frontend/src/screens/login/signup_flow/UserDetailsScreen.tsx @@ -1,15 +1,14 @@ -import React, { useState } from 'react'; -import { View, Text, KeyboardAvoidingView, Platform, ScrollView, TextInput } from 'react-native'; +import React, {useState } from 'react'; +import { View, Text } from 'react-native'; import { styled } from 'nativewind'; import Button from '../../../components/Button'; -import ProgressBar from '../../../components/ProgressBar'; import { useAuth } from '../../../context/AuthContext'; import TextInputComponent from '../components/TextInputComponent'; +import NavProgressBar from '../components/NavProgressBar'; +import OnboardingScreenWrapper from '../components/OnboardingScreenWrapper'; const StyledView = styled(View); const StyledText = styled(Text); -const StyledKeyboardAvoidingView = styled(KeyboardAvoidingView); -const StyledScrollView = styled(ScrollView); export default function UserDetailsScreen({ navigation }) { const { signupData, updateSignupData } = useAuth(); @@ -23,17 +22,9 @@ export default function UserDetailsScreen({ navigation }) { }; return ( - - - - {/* Progress Bar */} - - - + + + navigation.goBack()} /> {/* User Details Input Section */} @@ -73,8 +64,7 @@ export default function UserDetailsScreen({ navigation }) { Continue - - - + + ); } diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 826918a..f3b618b 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -7593,7 +7593,7 @@ prompts@^2.0.1, prompts@^2.2.1, prompts@^2.3.2: kleur "^3.0.3" sisteransi "^1.0.5" -prop-types@^15.7.2, prop-types@^15.8.1: +prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== @@ -7764,6 +7764,19 @@ react-native-google-places-autocomplete@^2.5.7: qs "~6.9.1" uuid "^10.0.0" +react-native-iphone-x-helper@^1.0.3: + version "1.3.1" + resolved "https://registry.yarnpkg.com/react-native-iphone-x-helper/-/react-native-iphone-x-helper-1.3.1.tgz#20c603e9a0e765fd6f97396638bdeb0e5a60b010" + integrity sha512-HOf0jzRnq2/aFUcdCJ9w9JGzN3gdEg0zFE4FyYlp4jtidqU03D5X7ZegGKfT1EWteR0gPBGp9ye5T5FvSWi9Yg== + +react-native-keyboard-aware-scroll-view@^0.9.5: + version "0.9.5" + resolved "https://registry.yarnpkg.com/react-native-keyboard-aware-scroll-view/-/react-native-keyboard-aware-scroll-view-0.9.5.tgz#e2e9665d320c188e6b1f22f151b94eb358bf9b71" + integrity sha512-XwfRn+T/qBH9WjTWIBiJD2hPWg0yJvtaEw6RtPCa5/PYHabzBaWxYBOl0usXN/368BL1XktnZPh8C2lmTpOREA== + dependencies: + prop-types "^15.6.2" + react-native-iphone-x-helper "^1.0.3" + react-native-maps@1.18.0: version "1.18.0" resolved "https://registry.yarnpkg.com/react-native-maps/-/react-native-maps-1.18.0.tgz#48d253041a9baa5606b4f3647043d660a93b3b01"