chore: build
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import React, { useState, useEffect, useCallback, useRef } from "react";
|
||||
import { useFocusEffect } from "@react-navigation/native";
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
@@ -1155,9 +1156,25 @@ function CentralRewardSection({
|
||||
);
|
||||
}
|
||||
|
||||
// Palette violette d'origine de l'application (thème par défaut historique)
|
||||
const ORIGINAL_THEME_COLORS = {
|
||||
admin_color_primary: "#7c3aed",
|
||||
admin_color_secondary: "#000000",
|
||||
admin_color_success: "#4ade80",
|
||||
admin_color_danger: "#ef4444",
|
||||
admin_color_warning: "#f59e0b",
|
||||
client_color_primary: "#7c3aed",
|
||||
client_color_secondary: "#000000",
|
||||
client_color_success: "#4ade80",
|
||||
client_color_danger: "#ef4444",
|
||||
client_color_warning: "#f59e0b",
|
||||
client_title_gradient_from: "#a78bfa",
|
||||
client_title_gradient_to: "#22d3ee",
|
||||
} as const;
|
||||
|
||||
export default function SettingsScreen() {
|
||||
const { colors } = useTheme();
|
||||
const { alert, showError, showSuccess, hideAlert } = useAlert();
|
||||
const { colors, refreshColors } = useTheme();
|
||||
const { alert, showError, showSuccess, showConfirm, hideAlert } = useAlert();
|
||||
const navigation = useNavigation();
|
||||
const { width: screenWidth } = useWindowDimensions();
|
||||
const inputMd = screenWidth < 380 ? 64 : 80;
|
||||
@@ -1194,6 +1211,18 @@ export default function SettingsScreen() {
|
||||
shop_name: "Milieu-Nantais",
|
||||
contact_telegram: "",
|
||||
points_reward: null,
|
||||
admin_color_primary: "#7c3aed",
|
||||
admin_color_secondary: "#22d3ee",
|
||||
admin_color_success: "#4ade80",
|
||||
admin_color_danger: "#ef4444",
|
||||
admin_color_warning: "#f59e0b",
|
||||
client_color_primary: "#7c3aed",
|
||||
client_color_secondary: "#22d3ee",
|
||||
client_color_success: "#4ade80",
|
||||
client_color_danger: "#ef4444",
|
||||
client_color_warning: "#f59e0b",
|
||||
client_title_gradient_from: "#a78bfa",
|
||||
client_title_gradient_to: "#22d3ee",
|
||||
});
|
||||
const [showApiKey, setShowApiKey] = useState(false);
|
||||
const [showIpnSecret, setShowIpnSecret] = useState(false);
|
||||
@@ -1280,9 +1309,13 @@ export default function SettingsScreen() {
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
loadData();
|
||||
}, [loadData]);
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
if (!isDirty.current) {
|
||||
loadData();
|
||||
}
|
||||
}, [loadData])
|
||||
);
|
||||
|
||||
// Retourne l'index du pool auquel la catégorie est assignée, ou -1 si aucun
|
||||
const getPoolIndexFor = (catName: string): number => {
|
||||
@@ -1356,6 +1389,8 @@ export default function SettingsScreen() {
|
||||
setSaving(false);
|
||||
if (res.success) {
|
||||
isDirty.current = false;
|
||||
await loadData();
|
||||
await refreshColors();
|
||||
showSuccess("Succès", "Paramètres sauvegardés");
|
||||
} else {
|
||||
showError("Erreur", res.error || "Erreur lors de la sauvegarde");
|
||||
@@ -1484,6 +1519,7 @@ export default function SettingsScreen() {
|
||||
<ScrollView contentContainerStyle={s.content}>
|
||||
{/* Personnalisation */}
|
||||
<AccordionSection title="Personnalisation" colors={colors} s={s}>
|
||||
{/* Nom du shop */}
|
||||
<View style={[s.row, s.rowFirst]}>
|
||||
<View style={s.rowLeft}>
|
||||
<Text style={s.rowLabel}>Nom du shop</Text>
|
||||
@@ -1500,6 +1536,67 @@ export default function SettingsScreen() {
|
||||
autoCorrect={false}
|
||||
/>
|
||||
</View>
|
||||
|
||||
{/* Dégradé titre boutique */}
|
||||
<View style={{ borderTopWidth: 1, borderTopColor: colors.border, paddingHorizontal: spacing.l, paddingVertical: spacing.m, gap: spacing.m }}>
|
||||
<Text style={s.rowLabel}>Dégradé du titre boutique</Text>
|
||||
<Text style={s.rowDesc}>Couleurs du nom de la boutique dans le header du site client.</Text>
|
||||
|
||||
{/* Aperçu du dégradé */}
|
||||
<View style={{ height: 36, borderRadius: borderRadius.sm, overflow: "hidden" }}>
|
||||
<View style={{
|
||||
flex: 1,
|
||||
backgroundColor: settings.client_title_gradient_from,
|
||||
// gradient simulé : deux moitiés de couleur
|
||||
}}>
|
||||
<View style={{
|
||||
position: "absolute", right: 0, top: 0, bottom: 0,
|
||||
width: "50%",
|
||||
backgroundColor: settings.client_title_gradient_to,
|
||||
}} />
|
||||
<View style={{
|
||||
position: "absolute", left: "25%", right: "25%", top: 0, bottom: 0,
|
||||
backgroundColor: `${settings.client_title_gradient_from}00`,
|
||||
}} />
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Couleur de départ */}
|
||||
<View style={{ flexDirection: "row", alignItems: "center", gap: spacing.m }}>
|
||||
<View style={{ width: 32, height: 32, borderRadius: borderRadius.sm, backgroundColor: settings.client_title_gradient_from, borderWidth: 1, borderColor: colors.border }} />
|
||||
<View style={{ flex: 1 }}>
|
||||
<Text style={[s.rowDesc, { marginBottom: 4 }]}>Couleur de départ</Text>
|
||||
<TextInput
|
||||
style={[s.input, { fontFamily: "monospace" }]}
|
||||
value={settings.client_title_gradient_from}
|
||||
onChangeText={(v) => setSettings((p) => ({ ...p, client_title_gradient_from: v }))}
|
||||
placeholder="#a78bfa"
|
||||
placeholderTextColor={colors.textMuted}
|
||||
autoCorrect={false}
|
||||
autoCapitalize="none"
|
||||
maxLength={7}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Couleur de fin */}
|
||||
<View style={{ flexDirection: "row", alignItems: "center", gap: spacing.m }}>
|
||||
<View style={{ width: 32, height: 32, borderRadius: borderRadius.sm, backgroundColor: settings.client_title_gradient_to, borderWidth: 1, borderColor: colors.border }} />
|
||||
<View style={{ flex: 1 }}>
|
||||
<Text style={[s.rowDesc, { marginBottom: 4 }]}>Couleur de fin</Text>
|
||||
<TextInput
|
||||
style={[s.input, { fontFamily: "monospace" }]}
|
||||
value={settings.client_title_gradient_to}
|
||||
onChangeText={(v) => setSettings((p) => ({ ...p, client_title_gradient_to: v }))}
|
||||
placeholder="#22d3ee"
|
||||
placeholderTextColor={colors.textMuted}
|
||||
autoCorrect={false}
|
||||
autoCapitalize="none"
|
||||
maxLength={7}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</AccordionSection>
|
||||
|
||||
{/* Amendes */}
|
||||
@@ -2182,6 +2279,97 @@ export default function SettingsScreen() {
|
||||
)}
|
||||
</AccordionSection>
|
||||
|
||||
{/* ============================================ */}
|
||||
{/* 🎨 COULEURS DE L'INTERFACE */}
|
||||
{/* ============================================ */}
|
||||
<AccordionSection title="Couleurs de l'interface" colors={colors} s={s}>
|
||||
<Text style={[s.hint, { paddingTop: spacing.s, paddingHorizontal: spacing.l }]}>
|
||||
Personnalisez les couleurs de l'espace admin et de l'app client / site web.
|
||||
</Text>
|
||||
|
||||
<TouchableOpacity
|
||||
onPress={() => showConfirm(
|
||||
"Restaurer le thème d'origine",
|
||||
"Toutes les couleurs personnalisées seront remplacées par le violet de base des premières versions de l'application. Continuer ?",
|
||||
() => {
|
||||
Keyboard.dismiss();
|
||||
setSettings((p) => ({ ...p, ...ORIGINAL_THEME_COLORS }));
|
||||
},
|
||||
"Restaurer",
|
||||
"Annuler",
|
||||
)}
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
gap: spacing.xs,
|
||||
marginHorizontal: spacing.l,
|
||||
marginTop: spacing.m,
|
||||
paddingVertical: spacing.s,
|
||||
paddingHorizontal: spacing.m,
|
||||
borderRadius: borderRadius.sm,
|
||||
borderWidth: 1,
|
||||
borderColor: "#7c3aed",
|
||||
alignSelf: "flex-start",
|
||||
}}
|
||||
>
|
||||
<Ionicons name="color-palette-outline" size={16} color="#7c3aed" />
|
||||
<Text style={{ fontSize: fontSize.sm, color: "#7c3aed", fontWeight: "600" }}>
|
||||
Restaurer les couleurs de base
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
{(["admin", "client"] as const).map((scope) => (
|
||||
<View key={scope}>
|
||||
<Text style={[s.rowLabel, { paddingHorizontal: spacing.l, paddingTop: spacing.l, paddingBottom: spacing.xs }]}>
|
||||
{scope === "admin" ? "Espace admin" : "App client & site web"}
|
||||
</Text>
|
||||
{([
|
||||
{ label: "Principale", key: `${scope}_color_primary` as const },
|
||||
{ label: "Secondaire", key: `${scope}_color_secondary` as const },
|
||||
{ label: "Succès", key: `${scope}_color_success` as const },
|
||||
{ label: "Danger", key: `${scope}_color_danger` as const },
|
||||
{ label: "Avertissement", key: `${scope}_color_warning` as const },
|
||||
] as { label: string; key: keyof typeof settings }[]).map(({ label, key }) => (
|
||||
<View key={key as string} style={{ paddingHorizontal: spacing.l, paddingBottom: spacing.m }}>
|
||||
<Text style={[s.rowDesc, { marginBottom: spacing.xs }]}>{label}</Text>
|
||||
<View style={{ flexDirection: "row", alignItems: "center", gap: spacing.m }}>
|
||||
<View style={{
|
||||
width: 36, height: 36,
|
||||
borderRadius: borderRadius.sm,
|
||||
backgroundColor: (settings[key] as string) || "#7c3aed",
|
||||
borderWidth: 1,
|
||||
borderColor: colors.border,
|
||||
}} />
|
||||
<TextInput
|
||||
style={[s.input, { flex: 1 }]}
|
||||
value={settings[key] as string}
|
||||
onChangeText={(v) => setSettings((p) => ({ ...p, [key]: v }))}
|
||||
placeholder="#7c3aed"
|
||||
placeholderTextColor={colors.textMuted}
|
||||
autoCapitalize="none"
|
||||
autoCorrect={false}
|
||||
/>
|
||||
</View>
|
||||
<View style={{ flexDirection: "row", gap: spacing.xs, marginTop: spacing.xs, flexWrap: "wrap" }}>
|
||||
{["#7c3aed", "#2563eb", "#0891b2", "#059669", "#d97706", "#dc2626", "#db2777", "#f59e0b", "#4ade80", "#ef4444", "#22d3ee", "#0f172a"].map((color) => (
|
||||
<TouchableOpacity
|
||||
key={color}
|
||||
onPress={() => setSettings((p) => ({ ...p, [key]: color }))}
|
||||
style={{
|
||||
width: 26, height: 26, borderRadius: 13,
|
||||
backgroundColor: color,
|
||||
borderWidth: (settings[key] as string) === color ? 2.5 : 1,
|
||||
borderColor: (settings[key] as string) === color ? colors.textPrimary : colors.border,
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</View>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
))}
|
||||
</AccordionSection>
|
||||
|
||||
<TouchableOpacity
|
||||
style={s.saveButton}
|
||||
onPress={handleSave}
|
||||
|
||||
Reference in New Issue
Block a user