login style

This commit is contained in:
2025-10-12 13:58:14 +02:00
parent 31e81ef83d
commit b34479762a
2 changed files with 213 additions and 112 deletions
@@ -1,23 +1,74 @@
import { View, StyleSheet } from "react-native"; import { View, StyleSheet } from "react-native";
import React, { useState } from "react"; import React, { useMemo, useState } from "react";
import omit from "lodash/omit";
import BorderGradient from "../BorderGradient/BorderGradient"; import BorderGradient from "../BorderGradient/BorderGradient";
import { responsiveHeight } from "react-native-responsive-dimensions"; import { responsiveHeight } from "react-native-responsive-dimensions";
import { BlurView } from "expo-blur"; import { BlurView } from "expo-blur";
import { Style } from "../../styles"; import { Style } from "../../styles";
const ITEM_BORDER_RADIUS = 24;
const CONTAINER_STYLE_PROPS = [
"margin",
"marginTop",
"marginBottom",
"marginLeft",
"marginRight",
"marginHorizontal",
"marginVertical",
"alignSelf",
"alignItems",
"justifyContent",
"width",
"minWidth",
"maxWidth",
];
const ItemContainer = ({ const ItemContainer = ({
height = responsiveHeight(40), height = responsiveHeight(40),
width,
maxWidth,
children, children,
gradientProps, gradientProps,
style, style,
disableKeyboardHeight = false, // parity with native signature
}) => { }) => {
const [containerLayout, setContainerLayout] = useState(null); const [containerLayout, setContainerLayout] = useState(null);
const flattenedStyle = StyleSheet.flatten(style) || {};
const containerStyleOverrides = useMemo(() => {
return CONTAINER_STYLE_PROPS.reduce((acc, key) => {
if (typeof flattenedStyle[key] !== "undefined") {
acc[key] = flattenedStyle[key];
}
return acc;
}, {});
}, [flattenedStyle]);
const {
width: styleWidth,
maxWidth: styleMaxWidth,
minWidth: styleMinWidth,
...remainingContainerStyle
} = containerStyleOverrides;
const gradientStyleOverrides = useMemo(
() => omit(flattenedStyle, CONTAINER_STYLE_PROPS),
[flattenedStyle]
);
const baseHeight = typeof height === "number" ? height : undefined;
const measuredHeight = containerLayout?.height ?? baseHeight;
const resolvedWidth = styleWidth ?? width ?? "100%";
const resolvedMaxWidth = styleMaxWidth ?? maxWidth;
return ( return (
<View <View
style={{ style={[
...styles.blurContainer, styles.wrapper,
}} remainingContainerStyle,
{ width: resolvedWidth },
resolvedMaxWidth ? { maxWidth: resolvedMaxWidth } : null,
styleMinWidth ? { minWidth: styleMinWidth } : null,
]}
> >
<BorderGradient <BorderGradient
gradientProps={{ gradientProps={{
@@ -27,34 +78,26 @@ const ItemContainer = ({
locations: [0, 1], locations: [0, 1],
...gradientProps, ...gradientProps,
}} }}
style={{ style={[
...styles.borderGradientStyle, styles.borderGradientStyle,
height: containerLayout?.height, measuredHeight ? { height: measuredHeight } : null,
...style, gradientStyleOverrides,
}} ]}
/> />
<View <View
style={{ style={[
height, styles.contentWrapper,
...Style.containerCenter, Style.containerCenter,
borderRadius: 24, baseHeight ? { height: baseHeight } : null,
overflow: "hidden", ]}
zIndex: 1,
}}
onLayout={(e) => { onLayout={(e) => {
setContainerLayout(e.nativeEvent.layout); setContainerLayout(e.nativeEvent.layout);
}} }}
> >
<BlurView <BlurView
intensity={30} intensity={disableKeyboardHeight ? 35 : 45}
tint="dark" tint="dark"
style={{ style={styles.blurView}
padding: 6,
zIndex: 2,
width: "99.2%",
alignSelf: "center",
height: "99.2%",
}}
> >
{children} {children}
</BlurView> </BlurView>
@@ -66,18 +109,36 @@ const ItemContainer = ({
export default ItemContainer; export default ItemContainer;
const styles = StyleSheet.create({ const styles = StyleSheet.create({
wrapper: {
position: "relative",
alignSelf: "stretch",
},
borderGradientStyle: { borderGradientStyle: {
borderWidth: 1, borderWidth: 1.2,
borderRadius: 20, borderRadius: ITEM_BORDER_RADIUS,
shadowColor: "#000", shadowColor: "rgba(3, 0, 18, 0.58)",
shadowOffset: { shadowOffset: {
width: 0, width: 0,
height: 2, height: 2,
}, },
shadowOpacity: 0.25, shadowOpacity: 0.22,
shadowRadius: 3.84, shadowRadius: 18,
elevation: 100, elevation: 8,
position: "absolute", position: "absolute",
width: "100%", width: "100%",
}, },
contentWrapper: {
borderRadius: ITEM_BORDER_RADIUS,
overflow: "hidden",
zIndex: 1,
},
blurView: {
flex: 1,
width: "100%",
height: "100%",
paddingHorizontal: 32,
paddingVertical: 28,
justifyContent: "center",
alignSelf: "stretch",
},
}); });
+122 -82
View File
@@ -15,11 +15,11 @@ import {
} from "react-native"; } from "react-native";
import Svg, { Path } from "react-native-svg"; import Svg, { Path } from "react-native-svg";
import { useGlobal } from "reactn"; import { useGlobal } from "reactn";
import { handleFirebaseError } from "../actions/signupActions.js";
import { background } from "../assets"; import { background } from "../assets";
import GradientButton from "../components/GradientButton.js"; import GradientButton from "../components/GradientButton.js";
import { Input } from "../components/Input.js"; import { Input } from "../components/Input.js";
import ItemContainer from "../components/ItemContainer/ItemContainer"; import ItemContainer from "../components/ItemContainer/ItemContainer";
import { handleFirebaseError } from "../actions/signupActions.js";
import firebase, { usersRef } from "../config/firebase"; import firebase, { usersRef } from "../config/firebase";
import { import {
GOOGLE_ANDROID_CLIENT_ID, GOOGLE_ANDROID_CLIENT_ID,
@@ -114,8 +114,7 @@ export default ({ navigation }) => {
? handleFirebaseError(e.code) ? handleFirebaseError(e.code)
: e?.message; : e?.message;
setTooltip({ setTooltip({
text: text: message || "Connexion Google impossible. Merci de réessayer.",
message || "Connexion Google impossible. Merci de réessayer.",
type: "error", type: "error",
}); });
setLoading(false); setLoading(false);
@@ -202,37 +201,21 @@ export default ({ navigation }) => {
title={isWeb ? "" : "Connexion"} title={isWeb ? "" : "Connexion"}
hideBackButton hideBackButton
> >
<View <View style={styles.screen}>
style={{ <ItemContainer
flex: 1, height={isWeb ? 520 : 550}
justifyContent: "center", disableKeyboardHeight
alignItems: "center", style={styles.loginCard}
}} >
> <View style={styles.cardContent}>
<ItemContainer height={550} width={800} disableKeyboardHeight> <View style={styles.greetingSection}>
<View style={{ gap: 30, paddingTop: 5, paddingHorizontal: 5 }}> <Text style={styles.greetingTitle}>{"Bonjour !"}</Text>
<View style={{ gap: 2 }}> <Text style={styles.greetingSubtitle}>
<Text
style={{
fontSize: 22,
color: Palette.white,
fontFamily: FONT_FAMILY.InterSemiBold,
}}
>
{"Bonjour !"}
</Text>
<Text
style={{
fontSize: 14,
color: Palette.gray,
fontFamily: FONT_FAMILY.InterRegular,
}}
>
Nous sommes heureux de te revoir parmi nous. Prêt·e à reprendre Nous sommes heureux de te revoir parmi nous. Prêt·e à reprendre
le rythme ? le rythme ?
</Text> </Text>
</View> </View>
<View style={{ gap: 20 }}> <View style={styles.formFields}>
<Input <Input
placeholder="Adresse mail" placeholder="Adresse mail"
label="Adresse mail" label="Adresse mail"
@@ -241,7 +224,7 @@ export default ({ navigation }) => {
setValue={setEmail} setValue={setEmail}
isBlur isBlur
/> />
<View style={{ gap: 4 }}> <View style={styles.passwordField}>
<Input <Input
placeholder="Mot de passe" placeholder="Mot de passe"
label="Mot de passe" label="Mot de passe"
@@ -250,16 +233,14 @@ export default ({ navigation }) => {
setValue={setPassword} setValue={setPassword}
isBlur isBlur
/> />
<Pressable onPress={() => navigate(Routes.ForgotPassword)}> <Pressable
<Text onPress={() => navigate(Routes.ForgotPassword)}
style={{ style={({ pressed }) => [
fontSize: 12, styles.linkPressable,
color: Palette.white, pressed && styles.linkPressed,
fontFamily: FONT_FAMILY.HelveticaNeueRegular, ]}
}} >
> <Text style={styles.linkText}>Mot de passe oublié ?</Text>
Mot de passe oublié?
</Text>
</Pressable> </Pressable>
</View> </View>
</View> </View>
@@ -278,29 +259,16 @@ export default ({ navigation }) => {
loading={loading} loading={loading}
/> />
<View <View style={styles.signupWrapper}>
style={{ <Text style={styles.signupPrompt}>Pas encore de compte ?</Text>
alignItems: "center", <Pressable
gap: 4, onPress={() => navigate(Routes.Register)}
}} style={({ pressed }) => [
> styles.signupPressable,
<Pressable onPress={() => navigate(Routes.Register)}> pressed && styles.linkPressed,
<Text ]}
style={{ >
fontSize: 14, <Text style={styles.signupLink}>Créer un compte</Text>
color: Palette.white,
fontFamily: FONT_FAMILY.HelveticaNeueRegular,
}}
>
Pas encore de compte?{" "}
<Text
style={{
fontFamily: FONT_FAMILY.InterSemiBold,
}}
>
Créer un compte
</Text>
</Text>
</Pressable> </Pressable>
</View> </View>
</View> </View>
@@ -372,23 +340,94 @@ const getNativeGoogleRedirectUri = () => {
}; };
const styles = StyleSheet.create({ const styles = StyleSheet.create({
screen: {
flex: 1,
width: "100%",
justifyContent: "center",
alignItems: "center",
},
loginCard: {
width: "100%",
maxWidth: 520,
},
cardContent: {
gap: 28,
paddingTop: 8,
width: "100%",
},
greetingSection: {
gap: 6,
width: "100%",
},
greetingTitle: {
fontSize: 22,
color: Palette.white,
fontFamily: FONT_FAMILY.InterSemiBold,
},
greetingSubtitle: {
fontSize: 14,
color: Palette.gray,
fontFamily: FONT_FAMILY.InterRegular,
lineHeight: 20,
},
formFields: {
gap: 20,
width: "100%",
},
passwordField: {
gap: 8,
width: "100%",
},
linkPressable: {
alignSelf: "flex-end",
},
linkPressed: {
opacity: 0.6,
},
linkText: {
fontSize: 12,
color: Palette.white,
fontFamily: FONT_FAMILY.InterRegular,
textAlign: "right",
},
signupWrapper: {
flexDirection: "row",
flexWrap: "wrap",
alignItems: "center",
justifyContent: "center",
gap: 6,
},
signupPrompt: {
fontSize: 14,
color: Palette.white,
fontFamily: FONT_FAMILY.InterRegular,
},
signupPressable: {
paddingHorizontal: 2,
},
signupLink: {
fontSize: 14,
color: Palette.white,
fontFamily: FONT_FAMILY.InterSemiBold,
},
webButton: { webButton: {
alignSelf: "center", alignSelf: "center",
borderRadius: 12,
width: "80%", width: "80%",
height: 48,
borderRadius: 4,
backgroundColor: Palette.white, backgroundColor: Palette.white,
borderWidth: 1, borderWidth: 1,
borderColor: "#DADCE0", borderColor: "#E3E7EF",
justifyContent: "center", paddingVertical: 12,
shadowColor: "#000", paddingHorizontal: 20,
shadowOffset: { width: 0, height: 1 }, shadowColor: "rgba(12, 6, 34, 0.08)",
shadowOpacity: 0.12, shadowOffset: { width: 0, height: 8 },
shadowRadius: 2, shadowOpacity: 0.3,
elevation: 1, shadowRadius: 16,
elevation: 2,
}, },
webButtonPressed: { webButtonPressed: {
backgroundColor: "#F6F9FE", backgroundColor: "#F4F7FF",
}, },
webButtonDisabled: { webButtonDisabled: {
opacity: 0.7, opacity: 0.7,
@@ -396,24 +435,25 @@ const styles = StyleSheet.create({
webContent: { webContent: {
flexDirection: "row", flexDirection: "row",
alignItems: "center", alignItems: "center",
justifyContent: "center", justifyContent: "space-between",
paddingHorizontal: 12, gap: 12,
}, },
webIconContainer: { webIconContainer: {
justifyContent: "center", justifyContent: "center",
alignItems: "center", alignItems: "center",
marginRight: 12, width: 28,
height: 28,
}, },
webText: { webText: {
flex: 1, flex: 1,
textAlign: "center", textAlign: "center",
fontSize: 14, fontSize: 15,
color: "#3C4043", color: "#202124",
fontFamily: FONT_FAMILY.InterSemiBold, fontFamily: FONT_FAMILY.InterSemiBold,
}, },
webRightSpacer: { webRightSpacer: {
width: 18, width: 24,
height: 18, height: 24,
}, },
nativeButtonWrapper: { nativeButtonWrapper: {
alignSelf: "center", alignSelf: "center",
@@ -433,7 +473,7 @@ const styles = StyleSheet.create({
}); });
const GoogleLogo = () => ( const GoogleLogo = () => (
<Svg width={18} height={18} viewBox="0 0 18 18"> <Svg width={24} height={24} viewBox="0 0 18 18">
<Path <Path
fill="#4285F4" fill="#4285F4"
d="M17.64 9.2c0-.64-.06-1.25-.16-1.84H9v3.48h4.84a4.14 4.14 0 0 1-1.8 2.71v2.26h2.9c1.68-1.55 2.7-3.83 2.7-6.61Z" d="M17.64 9.2c0-.64-.06-1.25-.16-1.84H9v3.48h4.84a4.14 4.14 0 0 1-1.8 2.71v2.26h2.9c1.68-1.55 2.7-3.83 2.7-6.61Z"