chore: update

This commit is contained in:
2026-03-08 19:55:27 +01:00
parent 70b1f26425
commit 5329fa1b27
3 changed files with 102 additions and 25 deletions
@@ -585,6 +585,11 @@ export default function OrderDetailScreen() {
<Text style={styles.info}> <Text style={styles.info}>
Total: {command.total_prix?.toFixed(2)} Total: {command.total_prix?.toFixed(2)}
</Text> </Text>
{command.referral_used > 0 && (
<Text style={[styles.info, { color: colors.success }]}>
Parrainage utilisé: -{command.referral_used?.toFixed(2)}
</Text>
)}
{command.livreur_assign && ( {command.livreur_assign && (
<Text style={styles.info}> <Text style={styles.info}>
Livreur: {command.livreur_assign} Livreur: {command.livreur_assign}
@@ -29,6 +29,7 @@ function TiersSection({
colors, colors,
s, s,
accentColor, accentColor,
active,
}: { }: {
title: string; title: string;
tiers: PointsTier[]; tiers: PointsTier[];
@@ -36,6 +37,7 @@ function TiersSection({
colors: any; colors: any;
s: any; s: any;
accentColor: string; accentColor: string;
active: boolean;
}) { }) {
const updateTier = (i: number, field: keyof PointsTier, raw: string) => { const updateTier = (i: number, field: keyof PointsTier, raw: string) => {
const val = field === "points" ? parseInt(raw, 10) : parseFloat(raw); const val = field === "points" ? parseInt(raw, 10) : parseFloat(raw);
@@ -54,7 +56,22 @@ function TiersSection({
return ( return (
<View style={s.section}> <View style={s.section}>
<Text style={s.sectionTitle}>{title}</Text> <View style={{ flexDirection: "row", alignItems: "center", justifyContent: "space-between", paddingRight: spacing.l }}>
<Text style={s.sectionTitle}>{title}</Text>
<View style={{
paddingHorizontal: spacing.s,
paddingVertical: 2,
borderRadius: 10,
backgroundColor: active ? accentColor + "25" : colors.border + "40",
borderWidth: 1,
borderColor: active ? accentColor : colors.border,
marginBottom: spacing.s,
}}>
<Text style={{ fontSize: fontSize.xs, fontWeight: "700", color: active ? accentColor : colors.textMuted }}>
{active ? "Actif" : "Ignoré"}
</Text>
</View>
</View>
<Text style={s.hint}> <Text style={s.hint}>
Définissez chaque palier : de X à Y = N points.{"\n"} Définissez chaque palier : de X à Y = N points.{"\n"}
Max = 0 signifie illimité (pas de borne supérieure). Max = 0 signifie illimité (pas de borne supérieure).
@@ -319,10 +336,8 @@ export default function SettingsScreen() {
const ZIP_COLOR = "#9333ea"; const ZIP_COLOR = "#9333ea";
const TOTAL_COLOR = "#f97316"; const TOTAL_COLOR = "#f97316";
// Chips disponibles selon le mode // Tous les chips toujours disponibles — la config reste modifiable à tout moment
const availableChips: PoolAssignment[] = settings.points_separated const allChips: PoolAssignment[] = ["weed", "zipette", "total", "none"];
? ["weed", "zipette", "none"] // mode séparé : T désactivé
: ["total", "none"]; // mode non-séparé : W/Z désactivés
return ( return (
<View style={s.container}> <View style={s.container}>
@@ -430,29 +445,25 @@ export default function SettingsScreen() {
<Text style={s.sectionTitle}>Attribution des catégories aux points</Text> <Text style={s.sectionTitle}>Attribution des catégories aux points</Text>
<Text style={s.hint}> <Text style={s.hint}>
{settings.points_separated {settings.points_separated
? "Mode séparé : W = pool Weed, Z = pool Zipette." ? "Mode séparé actif : W et Z utilisés pour le calcul. T ignoré."
: "Mode non-séparé : T = pool Total (barème sur W+Z). W et Z désactivés."} : "Mode non-séparé actif : T utilisé pour le calcul. W et Z ignorés."}
{"\n"}Vous pouvez modifier les attributions à tout moment.
</Text> </Text>
{/* Légende */} {/* Légende */}
<View style={{ flexDirection: "row", gap: spacing.m, paddingHorizontal: spacing.l, paddingBottom: spacing.m, flexWrap: "wrap" }}> <View style={{ flexDirection: "row", gap: spacing.m, paddingHorizontal: spacing.l, paddingBottom: spacing.m, flexWrap: "wrap" }}>
{settings.points_separated ? ( <View style={{ flexDirection: "row", alignItems: "center", gap: spacing.xs }}>
<> <View style={[s.colorDot, { backgroundColor: WEED_COLOR }]} />
<View style={{ flexDirection: "row", alignItems: "center", gap: spacing.xs }}> <Text style={{ fontSize: fontSize.sm, color: colors.textMuted }}>Weed</Text>
<View style={[s.colorDot, { backgroundColor: WEED_COLOR }]} /> </View>
<Text style={{ fontSize: fontSize.sm, color: colors.textMuted }}>Weed</Text> <View style={{ flexDirection: "row", alignItems: "center", gap: spacing.xs }}>
</View> <View style={[s.colorDot, { backgroundColor: ZIP_COLOR }]} />
<View style={{ flexDirection: "row", alignItems: "center", gap: spacing.xs }}> <Text style={{ fontSize: fontSize.sm, color: colors.textMuted }}>Zipette</Text>
<View style={[s.colorDot, { backgroundColor: ZIP_COLOR }]} /> </View>
<Text style={{ fontSize: fontSize.sm, color: colors.textMuted }}>Zipette</Text> <View style={{ flexDirection: "row", alignItems: "center", gap: spacing.xs }}>
</View> <View style={[s.colorDot, { backgroundColor: TOTAL_COLOR }]} />
</> <Text style={{ fontSize: fontSize.sm, color: colors.textMuted }}>Total</Text>
) : ( </View>
<View style={{ flexDirection: "row", alignItems: "center", gap: spacing.xs }}>
<View style={[s.colorDot, { backgroundColor: TOTAL_COLOR }]} />
<Text style={{ fontSize: fontSize.sm, color: colors.textMuted }}>Total</Text>
</View>
)}
<View style={{ flexDirection: "row", alignItems: "center", gap: spacing.xs }}> <View style={{ flexDirection: "row", alignItems: "center", gap: spacing.xs }}>
<View style={[s.colorDot, { backgroundColor: colors.border }]} /> <View style={[s.colorDot, { backgroundColor: colors.border }]} />
<Text style={{ fontSize: fontSize.sm, color: colors.textMuted }}>Aucun</Text> <Text style={{ fontSize: fontSize.sm, color: colors.textMuted }}>Aucun</Text>
@@ -474,7 +485,7 @@ export default function SettingsScreen() {
/> />
<Text style={s.catName}>{cat.name}</Text> <Text style={s.catName}>{cat.name}</Text>
<View style={s.chips}> <View style={s.chips}>
{availableChips.map((p) => { {allChips.map((p) => {
const active = pool === p; const active = pool === p;
const chipColor = const chipColor =
p === "weed" p === "weed"
@@ -541,6 +552,7 @@ export default function SettingsScreen() {
colors={colors} colors={colors}
s={s} s={s}
accentColor={WEED_COLOR} accentColor={WEED_COLOR}
active={settings.points_separated}
/> />
<TiersSection <TiersSection
title="Barème Zipette" title="Barème Zipette"
@@ -549,6 +561,7 @@ export default function SettingsScreen() {
colors={colors} colors={colors}
s={s} s={s}
accentColor={ZIP_COLOR} accentColor={ZIP_COLOR}
active={settings.points_separated}
/> />
<TiersSection <TiersSection
title="Barème Total" title="Barème Total"
@@ -557,6 +570,7 @@ export default function SettingsScreen() {
colors={colors} colors={colors}
s={s} s={s}
accentColor={TOTAL_COLOR} accentColor={TOTAL_COLOR}
active={!settings.points_separated}
/> />
<TouchableOpacity <TouchableOpacity
@@ -6,6 +6,7 @@ import {
FlatList, FlatList,
RefreshControl, RefreshControl,
TouchableOpacity, TouchableOpacity,
TextInput as RNTextInput,
} from "react-native"; } from "react-native";
import { Ionicons } from "@expo/vector-icons"; import { Ionicons } from "@expo/vector-icons";
import { spacing, fontSize, borderRadius } from "../../theme"; import { spacing, fontSize, borderRadius } from "../../theme";
@@ -126,6 +127,7 @@ export default function UsersScreen() {
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [refreshing, setRefreshing] = useState(false); const [refreshing, setRefreshing] = useState(false);
const [filter, setFilter] = useState<RoleFilter>("all"); const [filter, setFilter] = useState<RoleFilter>("all");
const [search, setSearch] = useState("");
// Edit client modal // Edit client modal
const [editClientModal, setEditClientModal] = useState<{ const [editClientModal, setEditClientModal] = useState<{
@@ -224,6 +226,22 @@ export default function UsersScreen() {
merged = merged.filter((u) => u.role === filter); merged = merged.filter((u) => u.role === filter);
} }
if (search.trim()) {
const q = search.trim().toLowerCase();
merged = merged.filter((u) => {
if (u.username.toLowerCase().includes(q)) return true;
if (u.clientData) {
const c = u.clientData;
return (
c.nom.toLowerCase().includes(q) ||
c.prenom.toLowerCase().includes(q) ||
c.telephone.toLowerCase().includes(q)
);
}
return false;
});
}
return merged; return merged;
}; };
@@ -542,6 +560,26 @@ export default function UsersScreen() {
marginTop: spacing.xxl, marginTop: spacing.xxl,
}, },
// Search bar
searchContainer: {
flexDirection: "row",
alignItems: "center",
marginHorizontal: spacing.m,
marginBottom: spacing.s,
paddingHorizontal: spacing.m,
borderRadius: borderRadius.md,
backgroundColor: colors.bgSecondary,
borderWidth: 1,
borderColor: colors.border,
height: 44,
gap: spacing.s,
},
searchInput: {
flex: 1,
color: colors.textWhite,
fontSize: fontSize.sm,
},
// Add button // Add button
addButton: { addButton: {
flexDirection: "row", flexDirection: "row",
@@ -847,6 +885,26 @@ export default function UsersScreen() {
})} })}
</View> </View>
{/* Search bar */}
<View style={styles.searchContainer}>
<Ionicons name="search-outline" size={18} color={colors.textMuted} />
<RNTextInput
style={styles.searchInput}
placeholder="Rechercher par nom, username, téléphone..."
placeholderTextColor={colors.textMuted}
value={search}
onChangeText={setSearch}
autoCapitalize="none"
autoCorrect={false}
clearButtonMode="while-editing"
/>
{search.length > 0 && (
<TouchableOpacity onPress={() => setSearch("")}>
<Ionicons name="close-circle" size={18} color={colors.textMuted} />
</TouchableOpacity>
)}
</View>
{/* Add user button */} {/* Add user button */}
<TouchableOpacity <TouchableOpacity
style={styles.addButton} style={styles.addButton}