continue generating flow, add backend connection on main tabs

This commit is contained in:
Thomas Demirdjian
2025-08-28 17:18:28 +02:00
parent 0ca7544005
commit bb7b35626f
110 changed files with 1701 additions and 3408 deletions
+2 -1
View File
@@ -13,9 +13,10 @@ const BorderGradientButton = ({
titleStyle,
containerStyle = {},
tint = "dark",
disabled = false,
}) => {
return (
<Pressable onPress={onPress} style={{ ...containerStyle }}>
<Pressable onPress={onPress} disabled={disabled} style={{ ...containerStyle, opacity: disabled ? 0.6 : 1 }}>
<BorderGradient
gradientProps={{
colors: ["#F94697", "#7023F7"],
+41 -11
View File
@@ -3,6 +3,7 @@ import { View, Text, Image, Pressable, StyleSheet } from "react-native";
import { BlurView } from "expo-blur";
import Switch from "../components/Switch";
import OptionSelector from "../components/OptionSelector";
import { Container, Title, Input, Button } from "../components/Dialog";
import { Fonts, Style, gutters } from "../styles";
@@ -12,6 +13,15 @@ const labelOptions = {
name: "Nouveau nom",
email: "Nouvelle adresse email",
password: "Nouveau mot de passe",
language: "Nouvelle langue",
};
const languageOptions = {
fr: "Français",
en: "English",
es: "Español",
de: "Deutsch",
it: "Italiano",
};
export default ({ itemKey, type, value, title, onUpdateValue }) => {
@@ -51,7 +61,11 @@ export default ({ itemKey, type, value, title, onUpdateValue }) => {
},
})}
>
{itemKey === "password" ? "********" : value}
{itemKey === "password"
? "********"
: itemKey === "language"
? languageOptions[value] || value
: value}
</Text>
<Image
@@ -84,20 +98,36 @@ export default ({ itemKey, type, value, title, onUpdateValue }) => {
value={currentPassword}
onChangeText={(text) => setCurrentPassword(text)}
keyboardType="visible-password"
type={"password"}
containerStyle={{ marginBottom: gutters / 2 }}
/>
)}
{itemKey === "language" ? (
<OptionSelector
optionTypeList={languageOptions}
selected={inputData || "fr"}
setSelected={setInputData}
containerStyle={{ marginBottom: gutters / 2 }}
colorMap={{
fr: { primary: "#F94697", secondary: "#F946971A" },
en: { primary: "#7023F7", secondary: "#7023F71A" },
es: { primary: "#FDBA74", secondary: "#FDBA741A" },
de: { primary: "#60A5FA", secondary: "#60A5FA1A" },
it: { primary: "#34D399", secondary: "#34D3991A" },
}}
/>
) : (
<Input
label={labelOptions[itemKey]}
value={inputData}
onChangeText={(text) => setInputData(text)}
autoCapitalize={
["password", "email"].includes(itemKey) ? "none" : "words"
}
type={itemKey}
containerStyle={{ marginBottom: gutters / 2 }}
/>
)}
<Input
label={labelOptions[itemKey]}
value={inputData}
onChangeText={(text) => setInputData(text)}
autoCapitalize={
["password", "email"].includes(itemKey) ? "none" : "words"
}
type={itemKey}
containerStyle={{ marginBottom: gutters / 2 }}
/>
<Button
label="Valider"
onPress={() => {
+12 -1
View File
@@ -12,7 +12,7 @@ import { FONT_FAMILY } from "../styles/Fonts";
const INITIAL_BOX_SIZE = 6;
export default ({ value, maxValue, progress, onSeek, seekEnabled = false }) => {
export default ({ value, maxValue, progress, onSeek, onSeekStart, onSeekEnd, seekEnabled = false }) => {
const offset = useSharedValue(0);
const boxWidth = useSharedValue(INITIAL_BOX_SIZE);
const [layout, setLayout] = useState(null);
@@ -22,6 +22,12 @@ export default ({ value, maxValue, progress, onSeek, seekEnabled = false }) => {
const pan = Gesture.Pan()
.enabled(seekEnabled)
.onBegin(() => {
if (seekEnabled && typeof onSeekStart === 'function') {
// Notify JS thread that user started seeking (e.g., pause audio)
runOnJS(onSeekStart)();
}
})
.onChange((event) => {
offset.value =
Math.abs(offset.value) <= MAX_VALUE
@@ -40,6 +46,11 @@ export default ({ value, maxValue, progress, onSeek, seekEnabled = false }) => {
const ratio = MAX_VALUE > 0 ? Math.min(1, Math.max(0, offset.value / MAX_VALUE)) : 0;
// Reanimated -> JS thread bridge
runOnJS(onSeek)(ratio);
})
.onFinalize(() => {
if (seekEnabled && typeof onSeekEnd === 'function') {
runOnJS(onSeekEnd)();
}
});
// Reflect external progress into the slider UI
+53 -2
View File
@@ -1,17 +1,68 @@
import { View, Text } from "react-native";
import React from "react";
import React, { useGlobal } from "reactn";
import AppActionSheet from "../AppActionSheet";
import BorderGradientButton from "../BorderGradientButton";
import GradientButton from "../GradientButton";
import { Palette } from "../../styles";
import { FONT_FAMILY } from "../../styles/Fonts";
import { SheetManager } from "react-native-actions-sheet";
import alert from "../Alert";
import firebase, { usersRef } from "../../config/firebase";
import { reset } from "../../navigation/NavigationService";
import { Routes } from "../../navigation";
const DeleteAccountModal = () => {
const [currentUID] = useGlobal("currentUID");
const [, setTooltip] = useGlobal("_tooltip");
const onClose = async () => {
await SheetManager.hide("DeleteAccount");
};
const confirmDelete = () => {
alert(
"Êtes-vous sûr ?",
"Cette action supprimera votre profil.",
[
{ text: "Annuler", style: "cancel", onPress: () => {} },
{
text: "Confirmer",
onPress: () => {
alert(
"Confirmation",
"Dernière vérification: supprimer définitivement votre profil ?",
[
{ text: "Non", style: "cancel", onPress: () => {} },
{
text: "Oui, supprimer",
onPress: async () => {
try {
if (!currentUID) return;
await usersRef.doc(currentUID).delete();
// Sign out and reset navigation to Login
await firebase.auth().signOut();
reset({ index: 0, routes: [{ name: Routes.Login }] });
setTooltip({ type: "success", text: "Profil supprimé" });
} catch (e) {
setTooltip({
type: "error",
text: e?.message || "Suppression impossible",
});
} finally {
onClose();
}
},
},
],
{ cancelable: true },
);
},
},
],
{ cancelable: true },
);
};
return (
<AppActionSheet id="DeleteAccount">
<View style={{ gap: 20 }}>
@@ -39,7 +90,7 @@ const DeleteAccountModal = () => {
</Text>
</View>
<View style={{ width: "80%", alignSelf: "center", gap: 12 }}>
<BorderGradientButton title="Oui, supprimer" onPress={onClose} />
<BorderGradientButton title="Oui, supprimer" onPress={confirmDelete} />
<GradientButton title="Non, annuler" onPress={onClose} />
</View>
</View>