This commit is contained in:
@@ -1101,6 +1101,8 @@ export interface AppSettings {
|
||||
client_color_success: string;
|
||||
client_color_danger: string;
|
||||
client_color_warning: string;
|
||||
client_title_gradient_from: string;
|
||||
client_title_gradient_to: string;
|
||||
}
|
||||
|
||||
export const getSettings = async (): Promise<{
|
||||
|
||||
@@ -782,7 +782,7 @@ export default function OrdersScreen() {
|
||||
setOpenMenuId(null);
|
||||
handleForceValidate(item.id);
|
||||
},
|
||||
condition: !isDone && item.status !== "livre",
|
||||
condition: !isDone,
|
||||
},
|
||||
{
|
||||
label: "Supprimer",
|
||||
|
||||
@@ -1205,6 +1205,8 @@ export default function SettingsScreen() {
|
||||
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);
|
||||
@@ -1501,6 +1503,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>
|
||||
@@ -1517,6 +1520,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 */}
|
||||
|
||||
@@ -6,8 +6,8 @@ import {
|
||||
StyleSheet,
|
||||
RefreshControl,
|
||||
TouchableOpacity,
|
||||
Alert,
|
||||
} from "react-native";
|
||||
import AlertModal from "../../components/ui/AlertModal";
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
import { useFocusEffect } from "@react-navigation/native";
|
||||
import { useTheme } from "../../context/ThemeContext";
|
||||
@@ -197,6 +197,8 @@ export default function StatsScreen() {
|
||||
const [refreshing, setRefreshing] = useState(false);
|
||||
const [resetting, setResetting] = useState<StatSection | null>(null);
|
||||
const [prodSort, setProdSort] = useState<ProdSort>("quantity");
|
||||
const [confirmModal, setConfirmModal] = useState<{ section: StatSection; label: string } | null>(null);
|
||||
const [errorModal, setErrorModal] = useState<string | null>(null);
|
||||
|
||||
const loadStats = useCallback(async () => {
|
||||
try {
|
||||
@@ -215,25 +217,21 @@ export default function StatsScreen() {
|
||||
};
|
||||
|
||||
const handleReset = (section: StatSection, label: string) => {
|
||||
Alert.alert(
|
||||
`Réinitialiser — ${label}`,
|
||||
"Les données de cette section repartiront de zéro. Les commandes restent en base.\n\nConfirmer ?",
|
||||
[
|
||||
{ text: "Annuler", style: "cancel" },
|
||||
{
|
||||
text: "Réinitialiser",
|
||||
style: "destructive",
|
||||
onPress: async () => {
|
||||
setResetting(section);
|
||||
try {
|
||||
await resetAdminStats(section);
|
||||
await loadStats();
|
||||
} catch { /* ignore */ }
|
||||
setResetting(null);
|
||||
},
|
||||
},
|
||||
],
|
||||
);
|
||||
setConfirmModal({ section, label });
|
||||
};
|
||||
|
||||
const doReset = async () => {
|
||||
if (!confirmModal) return;
|
||||
const { section } = confirmModal;
|
||||
setConfirmModal(null);
|
||||
setResetting(section);
|
||||
try {
|
||||
await resetAdminStats(section);
|
||||
await loadStats();
|
||||
} catch (e: any) {
|
||||
setErrorModal(e?.response?.data?.error || e?.message || "Impossible de réinitialiser");
|
||||
}
|
||||
setResetting(null);
|
||||
};
|
||||
|
||||
// Produits triés selon le sélecteur
|
||||
@@ -271,6 +269,24 @@ export default function StatsScreen() {
|
||||
));
|
||||
|
||||
return (
|
||||
<>
|
||||
<AlertModal
|
||||
visible={confirmModal !== null}
|
||||
type="confirm"
|
||||
title={`Réinitialiser — ${confirmModal?.label ?? ""}`}
|
||||
message={`Les données "${confirmModal?.label ?? ""}" repartiront de zéro.\nLes commandes restent en base.`}
|
||||
confirmText="Réinitialiser"
|
||||
cancelText="Annuler"
|
||||
onClose={() => setConfirmModal(null)}
|
||||
onConfirm={doReset}
|
||||
/>
|
||||
<AlertModal
|
||||
visible={errorModal !== null}
|
||||
type="error"
|
||||
title="Erreur"
|
||||
message={errorModal ?? ""}
|
||||
onClose={() => setErrorModal(null)}
|
||||
/>
|
||||
<ScrollView
|
||||
style={styles.container}
|
||||
contentContainerStyle={styles.content}
|
||||
@@ -561,5 +577,6 @@ export default function StatsScreen() {
|
||||
)}
|
||||
</Section>
|
||||
</ScrollView>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user