diff --git a/.env.example b/.env.example index e69de29..25380d7 100644 --- a/.env.example +++ b/.env.example @@ -0,0 +1,6 @@ +EXPO_PUBLIC_FIREBASE_API_KEY= +EXPO_PUBLIC_FIREBASE_AUTH_DOMAIN= +EXPO_PUBLIC_FIREBASE_PROJECT_ID= +EXPO_PUBLIC_FIREBASE_STORAGE_BUCKET= +EXPO_PUBLIC_FIREBASE_MESSAGING_SENDER_ID= +EXPO_PUBLIC_FIREBASE_APP_ID= \ No newline at end of file diff --git a/app/(tabs)/_layout.tsx b/app/(tabs)/_layout.tsx index a763fb7..e8b2ef5 100644 --- a/app/(tabs)/_layout.tsx +++ b/app/(tabs)/_layout.tsx @@ -1,14 +1,14 @@ import { Tabs } from 'expo-router'; import React from 'react'; import {MaterialCommunityIcons} from "@expo/vector-icons"; - +import {Palette} from '@/constants/palette'; export default function TabLayout() { return ( - Session active Bienvenue - {user.displayName || user.email || user.uid} + {user.username || user.email || user.uid} @@ -63,22 +63,13 @@ const styles = StyleSheet.create({ gap: 20, backgroundColor: Palette.cream, }, - eyebrow: { - color: Palette.gray, - fontSize: 13, - fontWeight: '700', - letterSpacing: 1.1, - textTransform: 'uppercase', - }, title: { + ...Catamaran.extraBold34, color: Palette.black, - fontSize: 34, - fontWeight: '800', }, subtitle: { + ...FunnelSans.regular16, color: Palette.gray, - fontSize: 16, - lineHeight: 22, }, card: { gap: Spacing.sm, @@ -89,14 +80,13 @@ const styles = StyleSheet.create({ backgroundColor: Palette.white, }, label: { + ...FunnelSans.medium12, color: Palette.gray, - fontSize: 12, - fontWeight: '700', textTransform: 'uppercase', }, value: { + ...FunnelSans.regular16, color: Palette.black, - fontSize: 15, }, secondaryButton: { borderColor: Palette.black, diff --git a/app/_layout.tsx b/app/_layout.tsx index c514d7a..ceec77e 100644 --- a/app/_layout.tsx +++ b/app/_layout.tsx @@ -1,8 +1,33 @@ -import { Stack } from "expo-router"; -import { SafeAreaProvider } from "react-native-safe-area-context"; -import { AuthProvider } from "@/providers/AuthProvider"; +import { useFonts } from 'expo-font'; +import { SplashScreen, Stack } from 'expo-router'; +import { useEffect } from 'react'; +import { SafeAreaProvider } from 'react-native-safe-area-context'; + +import { AuthProvider } from '@/providers/AuthProvider'; + +SplashScreen.preventAutoHideAsync(); export default function RootLayout() { + const [fontsLoaded] = useFonts({ + 'Catamaran-SemiBold': require('@/assets/fonts/Catamaran/static/Catamaran-SemiBold.ttf'), + 'Catamaran-Bold': require('@/assets/fonts/Catamaran/static/Catamaran-Bold.ttf'), + 'Catamaran-ExtraBold': require('@/assets/fonts/Catamaran/static/Catamaran-ExtraBold.ttf'), + 'FunnelSans-Regular': require('@/assets/fonts/Funnel_Sans/static/FunnelSans-Regular.ttf'), + 'FunnelSans-Medium': require('@/assets/fonts/Funnel_Sans/static/FunnelSans-Medium.ttf'), + 'FunnelSans-SemiBold': require('@/assets/fonts/Funnel_Sans/static/FunnelSans-SemiBold.ttf'), + 'FunnelSans-Bold': require('@/assets/fonts/Funnel_Sans/static/FunnelSans-Bold.ttf'), + }); + + useEffect(() => { + if (fontsLoaded) { + SplashScreen.hideAsync(); + } + }, [fontsLoaded]); + + if (!fontsLoaded) { + return null; + } + return ( diff --git a/assets/fonts/Catamaran/Catamaran-VariableFont_wght.ttf b/assets/fonts/Catamaran/Catamaran-VariableFont_wght.ttf new file mode 100644 index 0000000..626132c Binary files /dev/null and b/assets/fonts/Catamaran/Catamaran-VariableFont_wght.ttf differ diff --git a/assets/fonts/Catamaran/OFL.txt b/assets/fonts/Catamaran/OFL.txt new file mode 100644 index 0000000..f83f3f5 --- /dev/null +++ b/assets/fonts/Catamaran/OFL.txt @@ -0,0 +1,93 @@ +Copyright 2014 The Catamaran Authors (pria.ravichandran@gmail.com) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +https://openfontlicense.org + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/assets/fonts/Catamaran/README.txt b/assets/fonts/Catamaran/README.txt new file mode 100644 index 0000000..fde2a5b --- /dev/null +++ b/assets/fonts/Catamaran/README.txt @@ -0,0 +1,71 @@ +Catamaran Variable Font +======================= + +This download contains Catamaran as both a variable font and static fonts. + +Catamaran is a variable font with this axis: + wght + +This means all the styles are contained in a single file: + Catamaran/Catamaran-VariableFont_wght.ttf + +If your app fully supports variable fonts, you can now pick intermediate styles +that aren’t available as static fonts. Not all apps support variable fonts, and +in those cases you can use the static font files for Catamaran: + Catamaran/static/Catamaran-Thin.ttf + Catamaran/static/Catamaran-ExtraLight.ttf + Catamaran/static/Catamaran-Light.ttf + Catamaran/static/Catamaran-Regular.ttf + Catamaran/static/Catamaran-Medium.ttf + Catamaran/static/Catamaran-SemiBold.ttf + Catamaran/static/Catamaran-Bold.ttf + Catamaran/static/Catamaran-ExtraBold.ttf + Catamaran/static/Catamaran-Black.ttf + +Get started +----------- + +1. Install the font files you want to use + +2. Use your app's font picker to view the font family and all the +available styles + +Learn more about variable fonts +------------------------------- + + https://developers.google.com/web/fundamentals/design-and-ux/typography/variable-fonts + https://variablefonts.typenetwork.com + https://medium.com/variable-fonts + +In desktop apps + + https://theblog.adobe.com/can-variable-fonts-illustrator-cc + https://helpx.adobe.com/nz/photoshop/using/fonts.html#variable_fonts + +Online + + https://developers.google.com/fonts/docs/getting_started + https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Fonts/Variable_Fonts_Guide + https://developer.microsoft.com/en-us/microsoft-edge/testdrive/demos/variable-fonts + +Installing fonts + + MacOS: https://support.apple.com/en-us/HT201749 + Linux: https://www.google.com/search?q=how+to+install+a+font+on+gnu%2Blinux + Windows: https://support.microsoft.com/en-us/help/314960/how-to-install-or-remove-a-font-in-windows + +Android Apps + + https://developers.google.com/fonts/docs/android + https://developer.android.com/guide/topics/ui/look-and-feel/downloadable-fonts + +License +------- +Please read the full license text (OFL.txt) to understand the permissions, +restrictions and requirements for usage, redistribution, and modification. + +You can use them in your products & projects – print or digital, +commercial or otherwise. + +This isn't legal advice, please consider consulting a lawyer and see the full +license for all details. diff --git a/assets/fonts/Catamaran/static/Catamaran-Black.ttf b/assets/fonts/Catamaran/static/Catamaran-Black.ttf new file mode 100644 index 0000000..7808ac9 Binary files /dev/null and b/assets/fonts/Catamaran/static/Catamaran-Black.ttf differ diff --git a/assets/fonts/Catamaran/static/Catamaran-Bold.ttf b/assets/fonts/Catamaran/static/Catamaran-Bold.ttf new file mode 100644 index 0000000..ea60cf8 Binary files /dev/null and b/assets/fonts/Catamaran/static/Catamaran-Bold.ttf differ diff --git a/assets/fonts/Catamaran/static/Catamaran-ExtraBold.ttf b/assets/fonts/Catamaran/static/Catamaran-ExtraBold.ttf new file mode 100644 index 0000000..8824b72 Binary files /dev/null and b/assets/fonts/Catamaran/static/Catamaran-ExtraBold.ttf differ diff --git a/assets/fonts/Catamaran/static/Catamaran-ExtraLight.ttf b/assets/fonts/Catamaran/static/Catamaran-ExtraLight.ttf new file mode 100644 index 0000000..25fa80d Binary files /dev/null and b/assets/fonts/Catamaran/static/Catamaran-ExtraLight.ttf differ diff --git a/assets/fonts/Catamaran/static/Catamaran-Light.ttf b/assets/fonts/Catamaran/static/Catamaran-Light.ttf new file mode 100644 index 0000000..08295eb Binary files /dev/null and b/assets/fonts/Catamaran/static/Catamaran-Light.ttf differ diff --git a/assets/fonts/Catamaran/static/Catamaran-Medium.ttf b/assets/fonts/Catamaran/static/Catamaran-Medium.ttf new file mode 100644 index 0000000..3d6a7b8 Binary files /dev/null and b/assets/fonts/Catamaran/static/Catamaran-Medium.ttf differ diff --git a/assets/fonts/Catamaran/static/Catamaran-Regular.ttf b/assets/fonts/Catamaran/static/Catamaran-Regular.ttf new file mode 100644 index 0000000..ee0e762 Binary files /dev/null and b/assets/fonts/Catamaran/static/Catamaran-Regular.ttf differ diff --git a/assets/fonts/Catamaran/static/Catamaran-SemiBold.ttf b/assets/fonts/Catamaran/static/Catamaran-SemiBold.ttf new file mode 100644 index 0000000..a5eeb54 Binary files /dev/null and b/assets/fonts/Catamaran/static/Catamaran-SemiBold.ttf differ diff --git a/assets/fonts/Catamaran/static/Catamaran-Thin.ttf b/assets/fonts/Catamaran/static/Catamaran-Thin.ttf new file mode 100644 index 0000000..c5c0f1d Binary files /dev/null and b/assets/fonts/Catamaran/static/Catamaran-Thin.ttf differ diff --git a/assets/fonts/Funnel_Sans/FunnelSans-Italic-VariableFont_wght.ttf b/assets/fonts/Funnel_Sans/FunnelSans-Italic-VariableFont_wght.ttf new file mode 100644 index 0000000..58de397 Binary files /dev/null and b/assets/fonts/Funnel_Sans/FunnelSans-Italic-VariableFont_wght.ttf differ diff --git a/assets/fonts/Funnel_Sans/FunnelSans-VariableFont_wght.ttf b/assets/fonts/Funnel_Sans/FunnelSans-VariableFont_wght.ttf new file mode 100644 index 0000000..2841abf Binary files /dev/null and b/assets/fonts/Funnel_Sans/FunnelSans-VariableFont_wght.ttf differ diff --git a/assets/fonts/Funnel_Sans/OFL.txt b/assets/fonts/Funnel_Sans/OFL.txt new file mode 100644 index 0000000..7cd5008 --- /dev/null +++ b/assets/fonts/Funnel_Sans/OFL.txt @@ -0,0 +1,93 @@ +Copyright 2024 The Funnel Project Authors (https://github.com/Dicotype/Funnel) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +https://openfontlicense.org + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/assets/fonts/Funnel_Sans/README.txt b/assets/fonts/Funnel_Sans/README.txt new file mode 100644 index 0000000..0be7f65 --- /dev/null +++ b/assets/fonts/Funnel_Sans/README.txt @@ -0,0 +1,75 @@ +Funnel Sans Variable Font +========================= + +This download contains Funnel Sans as both variable fonts and static fonts. + +Funnel Sans is a variable font with this axis: + wght + +This means all the styles are contained in these files: + Funnel_Sans/FunnelSans-VariableFont_wght.ttf + Funnel_Sans/FunnelSans-Italic-VariableFont_wght.ttf + +If your app fully supports variable fonts, you can now pick intermediate styles +that aren’t available as static fonts. Not all apps support variable fonts, and +in those cases you can use the static font files for Funnel Sans: + Funnel_Sans/static/FunnelSans-Light.ttf + Funnel_Sans/static/FunnelSans-Regular.ttf + Funnel_Sans/static/FunnelSans-Medium.ttf + Funnel_Sans/static/FunnelSans-SemiBold.ttf + Funnel_Sans/static/FunnelSans-Bold.ttf + Funnel_Sans/static/FunnelSans-ExtraBold.ttf + Funnel_Sans/static/FunnelSans-LightItalic.ttf + Funnel_Sans/static/FunnelSans-Italic.ttf + Funnel_Sans/static/FunnelSans-MediumItalic.ttf + Funnel_Sans/static/FunnelSans-SemiBoldItalic.ttf + Funnel_Sans/static/FunnelSans-BoldItalic.ttf + Funnel_Sans/static/FunnelSans-ExtraBoldItalic.ttf + +Get started +----------- + +1. Install the font files you want to use + +2. Use your app's font picker to view the font family and all the +available styles + +Learn more about variable fonts +------------------------------- + + https://developers.google.com/web/fundamentals/design-and-ux/typography/variable-fonts + https://variablefonts.typenetwork.com + https://medium.com/variable-fonts + +In desktop apps + + https://theblog.adobe.com/can-variable-fonts-illustrator-cc + https://helpx.adobe.com/nz/photoshop/using/fonts.html#variable_fonts + +Online + + https://developers.google.com/fonts/docs/getting_started + https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Fonts/Variable_Fonts_Guide + https://developer.microsoft.com/en-us/microsoft-edge/testdrive/demos/variable-fonts + +Installing fonts + + MacOS: https://support.apple.com/en-us/HT201749 + Linux: https://www.google.com/search?q=how+to+install+a+font+on+gnu%2Blinux + Windows: https://support.microsoft.com/en-us/help/314960/how-to-install-or-remove-a-font-in-windows + +Android Apps + + https://developers.google.com/fonts/docs/android + https://developer.android.com/guide/topics/ui/look-and-feel/downloadable-fonts + +License +------- +Please read the full license text (OFL.txt) to understand the permissions, +restrictions and requirements for usage, redistribution, and modification. + +You can use them in your products & projects – print or digital, +commercial or otherwise. + +This isn't legal advice, please consider consulting a lawyer and see the full +license for all details. diff --git a/assets/fonts/Funnel_Sans/static/FunnelSans-Bold.ttf b/assets/fonts/Funnel_Sans/static/FunnelSans-Bold.ttf new file mode 100644 index 0000000..7146dc6 Binary files /dev/null and b/assets/fonts/Funnel_Sans/static/FunnelSans-Bold.ttf differ diff --git a/assets/fonts/Funnel_Sans/static/FunnelSans-BoldItalic.ttf b/assets/fonts/Funnel_Sans/static/FunnelSans-BoldItalic.ttf new file mode 100644 index 0000000..8f2546b Binary files /dev/null and b/assets/fonts/Funnel_Sans/static/FunnelSans-BoldItalic.ttf differ diff --git a/assets/fonts/Funnel_Sans/static/FunnelSans-ExtraBold.ttf b/assets/fonts/Funnel_Sans/static/FunnelSans-ExtraBold.ttf new file mode 100644 index 0000000..b82027a Binary files /dev/null and b/assets/fonts/Funnel_Sans/static/FunnelSans-ExtraBold.ttf differ diff --git a/assets/fonts/Funnel_Sans/static/FunnelSans-ExtraBoldItalic.ttf b/assets/fonts/Funnel_Sans/static/FunnelSans-ExtraBoldItalic.ttf new file mode 100644 index 0000000..711dfce Binary files /dev/null and b/assets/fonts/Funnel_Sans/static/FunnelSans-ExtraBoldItalic.ttf differ diff --git a/assets/fonts/Funnel_Sans/static/FunnelSans-Italic.ttf b/assets/fonts/Funnel_Sans/static/FunnelSans-Italic.ttf new file mode 100644 index 0000000..8274598 Binary files /dev/null and b/assets/fonts/Funnel_Sans/static/FunnelSans-Italic.ttf differ diff --git a/assets/fonts/Funnel_Sans/static/FunnelSans-Light.ttf b/assets/fonts/Funnel_Sans/static/FunnelSans-Light.ttf new file mode 100644 index 0000000..9d05065 Binary files /dev/null and b/assets/fonts/Funnel_Sans/static/FunnelSans-Light.ttf differ diff --git a/assets/fonts/Funnel_Sans/static/FunnelSans-LightItalic.ttf b/assets/fonts/Funnel_Sans/static/FunnelSans-LightItalic.ttf new file mode 100644 index 0000000..afc2d59 Binary files /dev/null and b/assets/fonts/Funnel_Sans/static/FunnelSans-LightItalic.ttf differ diff --git a/assets/fonts/Funnel_Sans/static/FunnelSans-Medium.ttf b/assets/fonts/Funnel_Sans/static/FunnelSans-Medium.ttf new file mode 100644 index 0000000..29a014e Binary files /dev/null and b/assets/fonts/Funnel_Sans/static/FunnelSans-Medium.ttf differ diff --git a/assets/fonts/Funnel_Sans/static/FunnelSans-MediumItalic.ttf b/assets/fonts/Funnel_Sans/static/FunnelSans-MediumItalic.ttf new file mode 100644 index 0000000..ba25a24 Binary files /dev/null and b/assets/fonts/Funnel_Sans/static/FunnelSans-MediumItalic.ttf differ diff --git a/assets/fonts/Funnel_Sans/static/FunnelSans-Regular.ttf b/assets/fonts/Funnel_Sans/static/FunnelSans-Regular.ttf new file mode 100644 index 0000000..3e497ba Binary files /dev/null and b/assets/fonts/Funnel_Sans/static/FunnelSans-Regular.ttf differ diff --git a/assets/fonts/Funnel_Sans/static/FunnelSans-SemiBold.ttf b/assets/fonts/Funnel_Sans/static/FunnelSans-SemiBold.ttf new file mode 100644 index 0000000..195dc97 Binary files /dev/null and b/assets/fonts/Funnel_Sans/static/FunnelSans-SemiBold.ttf differ diff --git a/assets/fonts/Funnel_Sans/static/FunnelSans-SemiBoldItalic.ttf b/assets/fonts/Funnel_Sans/static/FunnelSans-SemiBoldItalic.ttf new file mode 100644 index 0000000..934ac9c Binary files /dev/null and b/assets/fonts/Funnel_Sans/static/FunnelSans-SemiBoldItalic.ttf differ diff --git a/bun.lock b/bun.lock index 9c13c5d..27f5bd9 100644 --- a/bun.lock +++ b/bun.lock @@ -23,6 +23,7 @@ "expo-system-ui": "~6.0.9", "expo-web-browser": "~15.0.10", "firebase": "^12.12.0", + "moment": "^2.30.1", "react": "19.1.0", "react-dom": "19.1.0", "react-native": "0.81.5", @@ -1340,6 +1341,8 @@ "mkdirp": ["mkdirp@1.0.4", "", { "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="], + "moment": ["moment@2.30.1", "", {}, "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how=="], + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], "mz": ["mz@2.7.0", "", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="], diff --git a/components/auth/AuthForm.tsx b/components/auth/AuthForm.tsx index 95714c6..01bbee7 100644 --- a/components/auth/AuthForm.tsx +++ b/components/auth/AuthForm.tsx @@ -6,12 +6,13 @@ import { Platform, StyleSheet, Text, - TextInput, View, } from 'react-native'; import { SafeAreaView } from 'react-native-safe-area-context'; import { Button } from '@/components/common/Button'; +import { Catamaran, FunnelSans } from '@/constants/fonts'; +import { Input } from '@/components/common/Input'; import { Palette } from '@/constants/palette'; import { Radius, Spacing } from '@/constants/styles'; import { mapFirebaseAuthError } from '@/lib/firebase-auth-errors'; @@ -40,7 +41,7 @@ const copyByMode = { export function AuthForm({ mode }: AuthFormProps) { const copy = copyByMode[mode]; - const [displayName, setDisplayName] = useState(''); + const [username, setUsername] = useState(''); const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [error, setError] = useState(null); @@ -51,12 +52,12 @@ export function AuthForm({ mode }: AuthFormProps) { return false; } - if (mode === 'register' && !displayName.trim()) { + if (mode === 'register' && !username.trim()) { return false; } return true; - }, [displayName, email, mode, password]); + }, [username, email, mode, password]); const handleSubmit = async () => { if (!isFormValid || isSubmitting) { @@ -73,7 +74,7 @@ export function AuthForm({ mode }: AuthFormProps) { await registerWithEmail({ email, password, - displayName, + username, }); } } catch (submitError) { @@ -96,46 +97,37 @@ export function AuthForm({ mode }: AuthFormProps) { {mode === 'register' ? ( - - Nom - - + ) : null} - - Email - - + - - Mot de passe - - + {error ? {error} : null} @@ -180,14 +172,12 @@ const styles = StyleSheet.create({ }, title: { + ...Catamaran.extraBold36, color: Palette.black, - fontSize: 36, - fontWeight: '800', }, subtitle: { + ...FunnelSans.regular16, color: Palette.gray, - fontSize: 16, - lineHeight: 22, }, card: { @@ -199,27 +189,11 @@ const styles = StyleSheet.create({ gap: Spacing.md, }, field: { - gap: Spacing.sm, - }, - label: { - color: Palette.black, - fontSize: 14, - fontWeight: '600', - }, - input: { - borderWidth: 1, - borderColor: Palette.gray, - borderRadius: Radius.lg, - backgroundColor: Palette.white, - color: Palette.black, - fontSize: 16, - paddingHorizontal: Spacing.md, - paddingVertical: 14, + width: '100%', }, error: { + ...FunnelSans.semiBold14, color: Palette.danger, - fontSize: 14, - lineHeight: 20, }, submitButton: { minHeight: 52, @@ -228,9 +202,8 @@ const styles = StyleSheet.create({ marginTop: -4, }, switchLink: { + ...FunnelSans.semiBold14, color: Palette.black, - fontSize: 14, - fontWeight: '600', textAlign: 'center', textDecorationLine: 'underline', }, diff --git a/components/common/Button.tsx b/components/common/Button.tsx index 39877c7..94607c3 100644 --- a/components/common/Button.tsx +++ b/components/common/Button.tsx @@ -7,6 +7,7 @@ import { TextStyle, } from "react-native"; import {Palette} from "@/constants/palette"; +import { FunnelSans } from "@/constants/fonts"; import { Radius, Spacing } from "@/constants/styles"; type ButtonVariant = "primary" | "secondary"; @@ -88,7 +89,7 @@ const styles = StyleSheet.create({ borderWidth: 1, }, text: { - fontWeight: "500", + ...FunnelSans.medium16, }, disabled: { opacity: 0.5, diff --git a/components/common/Input.tsx b/components/common/Input.tsx index e69de29..ab75878 100644 --- a/components/common/Input.tsx +++ b/components/common/Input.tsx @@ -0,0 +1,70 @@ +import React from 'react'; +import { + StyleSheet, + Text, + TextInput, + type StyleProp, + type TextInputProps, + type TextStyle, + type ViewStyle, + View, +} from 'react-native'; + +import { Palette } from '@/constants/palette'; +import { FunnelSans } from '@/constants/fonts'; +import { Radius, Spacing } from '@/constants/styles'; + +type InputProps = TextInputProps & { + label?: string; + error?: string | null; + containerStyle?: StyleProp; + inputStyle?: StyleProp; +}; + +export function Input({ + label, + error, + containerStyle, + inputStyle, + ...textInputProps +}: InputProps) { + return ( + + {label ? {label} : null} + + + + {error ? {error} : null} + + ); +} + +export default Input; + +const styles = StyleSheet.create({ + container: { + gap: Spacing.sm, + }, + label: { + ...FunnelSans.semiBold14, + color: Palette.black, + }, + input: { + ...FunnelSans.regular16, + borderWidth: 1, + borderColor: Palette.gray, + borderRadius: Radius.lg, + backgroundColor: Palette.white, + color: Palette.black, + paddingHorizontal: Spacing.md, + paddingVertical: 14, + }, + error: { + ...FunnelSans.semiBold14, + color: Palette.danger, + }, +}); diff --git a/constants/fonts.ts b/constants/fonts.ts new file mode 100644 index 0000000..39c96dc --- /dev/null +++ b/constants/fonts.ts @@ -0,0 +1,27 @@ +import { StyleSheet } from 'react-native'; + +const createFontStyle = ( + fontFamily: string, + fontSize: number, + lineHeight: number +) => ({ + fontFamily, + fontSize, + lineHeight, +}); + +export const Catamaran = StyleSheet.create({ + semiBold18: createFontStyle('Catamaran-SemiBold', 18, 24), + bold18: createFontStyle('Catamaran-Bold', 18, 24), + extraBold34: createFontStyle('Catamaran-ExtraBold', 34, 40), + extraBold36: createFontStyle('Catamaran-ExtraBold', 36, 42), +}); + +export const FunnelSans = StyleSheet.create({ + regular16: createFontStyle('FunnelSans-Regular', 16, 22), + medium12: createFontStyle('FunnelSans-Medium', 12, 16), + medium14: createFontStyle('FunnelSans-Medium', 14, 20), + medium16: createFontStyle('FunnelSans-Medium', 16, 22), + semiBold14: createFontStyle('FunnelSans-SemiBold', 14, 20), + bold16: createFontStyle('FunnelSans-Bold', 16, 22), +}); diff --git a/constants/palette.ts b/constants/palette.ts index 1d3d0bd..915b92d 100644 --- a/constants/palette.ts +++ b/constants/palette.ts @@ -5,4 +5,8 @@ export const Palette = { cream: '#f5efe6', gray: '#5a5148', danger: '#9f2d2d', + + tab: { + active: '#426fb3', + } }; diff --git a/lib/firebase-auth-errors.ts b/lib/firebase-auth-errors.ts index 994bb52..fafd921 100644 --- a/lib/firebase-auth-errors.ts +++ b/lib/firebase-auth-errors.ts @@ -6,7 +6,7 @@ const firebaseAuthErrorMessages: Record = { }; const defaultFirebaseAuthErrorMessage = - "Une erreur est survenue. Verifie ta configuration Firebase."; + "Une erreur est survenue."; export function mapFirebaseAuthError(error: unknown) { const message = error instanceof Error ? error.message : String(error); diff --git a/lib/firestore.ts b/lib/firestore.ts index 38f95c0..cc1ea6d 100644 --- a/lib/firestore.ts +++ b/lib/firestore.ts @@ -3,32 +3,67 @@ import { doc, type DocumentData, type FirestoreDataConverter, - type PartialWithFieldValue, type QueryDocumentSnapshot, - type SetOptions, type SnapshotOptions, - type WithFieldValue, } from 'firebase/firestore'; import { db } from '@/lib/firebase'; -import type { UserDocument } from '@/types/firestore'; +import type { UserDocument, UserFirestoreDocument } from '@/types/firestore'; -const converter = (): FirestoreDataConverter => ({ - toFirestore: (value: WithFieldValue | PartialWithFieldValue, options?: SetOptions) => - value as DocumentData, +type TimestampFieldValue = { + toDate: () => Date; +}; + +function hasToDate(value: unknown): value is TimestampFieldValue { + return ( + typeof value === 'object' && + value !== null && + 'toDate' in value && + typeof value.toDate === 'function' + ); +} + +export function mapTimestampFields< + Source extends Record, + Result extends Record, +>(data: Source, fields: Array) { + const nextData = { ...data } as Record; + + for (const field of fields) { + const value = nextData[field as string]; + + if (hasToDate(value)) { + nextData[field as string] = value.toDate(); + } + } + + return nextData as Result; +} + +const converter = ( + fromFirestoreMapper: (data: DbModel) => AppModel +): FirestoreDataConverter => ({ + toFirestore: (value) => value as DocumentData, fromFirestore: ( snapshot: QueryDocumentSnapshot, options: SnapshotOptions - ) => snapshot.data(options) as T, + ) => fromFirestoreMapper(snapshot.data(options) as DbModel), }); +const userConverter = converter((data) => + mapTimestampFields(data, [ + 'createdAt', + 'updatedAt', + ]) +); + export const collectionNames = { users: 'users', } as const; -export const usersCollection = collection( - db, - collectionNames.users -).withConverter(converter()); +export const usersCollectionRef = collection(db, collectionNames.users); + +export const usersCollection = usersCollectionRef.withConverter(userConverter); export const userDoc = (uid: string) => doc(usersCollection, uid); +export const userDocRef = (uid: string) => doc(usersCollectionRef, uid); diff --git a/package.json b/package.json index 3460c17..eaecbed 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "expo-system-ui": "~6.0.9", "expo-web-browser": "~15.0.10", "firebase": "^12.12.0", + "moment": "^2.30.1", "react": "19.1.0", "react-dom": "19.1.0", "react-native": "0.81.5", diff --git a/providers/AuthProvider.tsx b/providers/AuthProvider.tsx index d33734b..b66a5b1 100644 --- a/providers/AuthProvider.tsx +++ b/providers/AuthProvider.tsx @@ -6,36 +6,69 @@ import { useState, type PropsWithChildren, } from 'react'; -import { onAuthStateChanged, type User } from 'firebase/auth'; +import { onAuthStateChanged, type User as FirebaseAuthUser } from 'firebase/auth'; +import { onSnapshot } from 'firebase/firestore'; import { auth } from '@/lib/firebase'; +import { userDoc } from '@/lib/firestore'; +import type { UserDocument } from '@/types/firestore'; type AuthContextValue = { - user: User | null; + authUser: FirebaseAuthUser | null; + user: UserDocument | null; initializing: boolean; }; const AuthContext = createContext(undefined); export function AuthProvider({ children }: PropsWithChildren) { - const [user, setUser] = useState(null); + const [authUser, setAuthUser] = useState(null); + const [user, setUser] = useState(null); const [initializing, setInitializing] = useState(true); useEffect(() => { + let unsubscribeUserSnapshot: (() => void) | undefined; + const unsubscribe = onAuthStateChanged(auth, (nextUser) => { - setUser(nextUser); - setInitializing(false); + setAuthUser(nextUser); + + if (unsubscribeUserSnapshot) { + unsubscribeUserSnapshot(); + unsubscribeUserSnapshot = undefined; + } + + if (!nextUser) { + setUser(null); + setInitializing(false); + return; + } + + unsubscribeUserSnapshot = onSnapshot( + userDoc(nextUser.uid), + (snapshot) => { + setUser(snapshot.data() ?? null); + setInitializing(false); + }, + () => { + setUser(null); + setInitializing(false); + } + ); }); - return unsubscribe; + return () => { + unsubscribe(); + unsubscribeUserSnapshot?.(); + }; }, []); const value = useMemo( () => ({ + authUser, user, initializing, }), - [initializing, user] + [authUser, initializing, user] ); return {children}; diff --git a/services/auth.ts b/services/auth.ts index 547f76b..302669d 100644 --- a/services/auth.ts +++ b/services/auth.ts @@ -7,12 +7,12 @@ import { import { serverTimestamp, setDoc } from 'firebase/firestore'; import { auth } from '@/lib/firebase'; -import { userDoc } from '@/lib/firestore'; +import { userDocRef } from '@/lib/firestore'; type RegisterParams = { email: string; password: string; - displayName: string; + username: string; }; export async function loginWithEmail(email: string, password: string) { @@ -22,25 +22,26 @@ export async function loginWithEmail(email: string, password: string) { export async function registerWithEmail({ email, password, - displayName, + username, }: RegisterParams) { + const normalizedEmail = email.trim(); + const normalizedUsername = username.trim(); + const credential = await createUserWithEmailAndPassword( auth, - email.trim(), + normalizedEmail, password ); - const normalizedDisplayName = displayName.trim(); - await updateProfile(credential.user, { - displayName: normalizedDisplayName, + displayName: normalizedUsername, }); - await setDoc(userDoc(credential.user.uid), { + await setDoc(userDocRef(credential.user.uid), { uid: credential.user.uid, - email: credential.user.email, - displayName: normalizedDisplayName, - photoURL: credential.user.photoURL, + email: credential.user.email ?? normalizedEmail, + username: normalizedUsername, + profilePicture: credential.user.photoURL, createdAt: serverTimestamp(), updatedAt: serverTimestamp(), }); diff --git a/types/firestore.ts b/types/firestore.ts index e097480..9524e7f 100644 --- a/types/firestore.ts +++ b/types/firestore.ts @@ -1,10 +1,19 @@ import type { Timestamp } from 'firebase/firestore'; export type UserDocument = { + uid: string; + email: string; + username: string | null; + profilePicture: string | null; + createdAt: Date; + updatedAt: Date; +}; + +export type UserFirestoreDocument = { uid: string; email: string | null; - displayName: string | null; - photoURL: string | null; + username: string | null; + profilePicture: string | null; createdAt: Timestamp; updatedAt: Timestamp; };