chore: fix

This commit is contained in:
2026-03-07 22:42:14 +01:00
parent 916d2a30ad
commit b0061cec8a
6 changed files with 203 additions and 43 deletions
+5
View File
@@ -663,10 +663,15 @@ export const deleteCategoryAdmin = async (
export interface AppSettings {
penalties_enabled: boolean;
show_amende_score: boolean;
points_enabled: boolean;
points_categories_weed: string[];
points_categories_zipette: string[];
points_separated: boolean;
points_weed_threshold_price: number;
points_weed_per_threshold: number;
points_zipette_threshold_price: number;
points_zipette_per_threshold: number;
}
export const getSettings = async (): Promise<{ success: boolean; settings?: AppSettings; error?: string }> => {
+5 -1
View File
@@ -346,7 +346,9 @@ export const getAllAlerts = async (): Promise<{
export interface PublicSettings {
penalties_enabled: boolean;
show_amende_score: boolean;
points_enabled: boolean;
points_separated: boolean;
}
export const getPublicSettings = async (): Promise<PublicSettings> => {
@@ -354,9 +356,11 @@ export const getPublicSettings = async (): Promise<PublicSettings> => {
const { data } = await apiClient.get(`http://5.181.0.112/api/v1/app-settings`);
return {
penalties_enabled: data.penalties_enabled ?? true,
show_amende_score: data.show_amende_score ?? true,
points_enabled: data.points_enabled ?? true,
points_separated: data.points_separated ?? true,
};
} catch {
return { penalties_enabled: true, points_enabled: true };
return { penalties_enabled: true, show_amende_score: true, points_enabled: true, points_separated: true };
}
};
@@ -7,6 +7,7 @@ import {
Switch,
TouchableOpacity,
ActivityIndicator,
TextInput,
} from "react-native";
import { Ionicons } from "@expo/vector-icons";
import { spacing, fontSize, borderRadius } from "../../theme";
@@ -26,10 +27,15 @@ export default function SettingsScreen() {
const [saving, setSaving] = useState(false);
const [settings, setSettings] = useState<AppSettings>({
penalties_enabled: true,
show_amende_score: true,
points_enabled: true,
points_categories_weed: [],
points_categories_zipette: [],
points_separated: true,
points_weed_threshold_price: 30,
points_weed_per_threshold: 1,
points_zipette_threshold_price: 30,
points_zipette_per_threshold: 1,
});
const [categories, setCategories] = useState<Category[]>([]);
@@ -142,6 +148,31 @@ export default function SettingsScreen() {
paddingHorizontal: spacing.l,
paddingBottom: spacing.m,
},
thresholdRow: {
flexDirection: "row",
alignItems: "center",
paddingHorizontal: spacing.l,
paddingVertical: spacing.m,
borderTopWidth: 1,
borderTopColor: colors.border,
gap: spacing.m,
},
thresholdLabel: { flex: 1, fontSize: fontSize.md, color: colors.textPrimary, fontWeight: "600" },
thresholdDesc: { fontSize: fontSize.sm, color: colors.textMuted, marginTop: 2 },
thresholdInputs: { flexDirection: "row", alignItems: "center", gap: spacing.s },
thresholdInput: {
backgroundColor: colors.bgPrimary,
borderWidth: 1,
borderColor: colors.border,
borderRadius: borderRadius.sm,
paddingHorizontal: spacing.s,
paddingVertical: 6,
color: colors.textPrimary,
fontSize: fontSize.md,
width: 64,
textAlign: "center",
},
thresholdSep: { fontSize: fontSize.md, color: colors.textMuted },
saveButton: {
backgroundColor: colors.accent,
borderRadius: borderRadius.lg,
@@ -188,6 +219,22 @@ export default function SettingsScreen() {
thumbColor="#fff"
/>
</View>
<View style={s.row}>
<View style={s.rowLeft}>
<Text style={s.rowLabel}>Afficher le score d'amendes</Text>
<Text style={s.rowDesc}>
Les clients et la cabine voient le nombre d'amendes
</Text>
</View>
<Switch
value={settings.show_amende_score}
onValueChange={(v) =>
setSettings((prev) => ({ ...prev, show_amende_score: v }))
}
trackColor={{ false: colors.border, true: colors.accent }}
thumbColor="#fff"
/>
</View>
</View>
{/* Système de points */}
@@ -324,6 +371,79 @@ export default function SettingsScreen() {
)}
</View>
{/* Barème de points */}
<View style={s.section}>
<Text style={s.sectionTitle}>Barème de points</Text>
<Text style={s.hint}>
Pour chaque tranche de prix dépensée, le client gagne un nombre de points.{"\n"}
Exemple : 50 = 2 pts 100 = 4 pts, 150 = 6 pts...
</Text>
{/* Weed */}
<View style={[s.thresholdRow, { borderTopWidth: 0 }]}>
<View style={{ flex: 1 }}>
<Text style={s.thresholdLabel}>Pool Weed / Hash</Text>
<Text style={s.thresholdDesc}>Prix seuil points gagnés</Text>
</View>
<View style={s.thresholdInputs}>
<TextInput
style={s.thresholdInput}
keyboardType="decimal-pad"
value={String(settings.points_weed_threshold_price)}
onChangeText={(v) => {
const n = parseFloat(v);
if (!isNaN(n) && n > 0)
setSettings((p) => ({ ...p, points_weed_threshold_price: n }));
}}
/>
<Text style={s.thresholdSep}> =</Text>
<TextInput
style={s.thresholdInput}
keyboardType="number-pad"
value={String(settings.points_weed_per_threshold)}
onChangeText={(v) => {
const n = parseInt(v, 10);
if (!isNaN(n) && n >= 0)
setSettings((p) => ({ ...p, points_weed_per_threshold: n }));
}}
/>
<Text style={s.thresholdSep}>pts</Text>
</View>
</View>
{/* Zipette */}
<View style={s.thresholdRow}>
<View style={{ flex: 1 }}>
<Text style={s.thresholdLabel}>Pool Zipette</Text>
<Text style={s.thresholdDesc}>Prix seuil points gagnés</Text>
</View>
<View style={s.thresholdInputs}>
<TextInput
style={s.thresholdInput}
keyboardType="decimal-pad"
value={String(settings.points_zipette_threshold_price)}
onChangeText={(v) => {
const n = parseFloat(v);
if (!isNaN(n) && n > 0)
setSettings((p) => ({ ...p, points_zipette_threshold_price: n }));
}}
/>
<Text style={s.thresholdSep}> =</Text>
<TextInput
style={s.thresholdInput}
keyboardType="number-pad"
value={String(settings.points_zipette_per_threshold)}
onChangeText={(v) => {
const n = parseInt(v, 10);
if (!isNaN(n) && n >= 0)
setSettings((p) => ({ ...p, points_zipette_per_threshold: n }));
}}
/>
<Text style={s.thresholdSep}>pts</Text>
</View>
</View>
</View>
<TouchableOpacity
style={s.saveButton}
onPress={handleSave}
@@ -19,7 +19,9 @@ export default function UsersScreen() {
const [refreshing, setRefreshing] = useState(false);
const [appSettings, setAppSettings] = useState<PublicSettings>({
penalties_enabled: true,
show_amende_score: true,
points_enabled: true,
points_separated: true,
});
const [penaltyModal, setPenaltyModal] = useState<{
visible: boolean;
@@ -145,6 +147,7 @@ export default function UsersScreen() {
</Text>
<View style={styles.statsRow}>
{appSettings.points_enabled && (
appSettings.points_separated ? (
<>
<View style={styles.stat}>
<Text style={[styles.statValue, { color: colors.success }]}>
@@ -159,8 +162,16 @@ export default function UsersScreen() {
<Text style={styles.statLabel}>Zipette</Text>
</View>
</>
) : (
<View style={styles.stat}>
<Text style={[styles.statValue, { color: colors.success }]}>
{item.point}
</Text>
<Text style={styles.statLabel}>Points</Text>
</View>
)
)}
{appSettings.penalties_enabled && (
{appSettings.show_amende_score && (
<View style={styles.stat}>
<Text style={[styles.statValue, { color: colors.warning }]}>
{item.amende}
+5 -1
View File
@@ -710,7 +710,9 @@ export const markNotificationsRead = async (): Promise<{
export interface PublicSettings {
penalties_enabled: boolean;
show_amende_score: boolean;
points_enabled: boolean;
points_separated: boolean;
}
export const getPublicSettings = async (): Promise<PublicSettings> => {
@@ -718,10 +720,12 @@ export const getPublicSettings = async (): Promise<PublicSettings> => {
const { data } = await apiClient.get(`${V1}/app-settings`);
return {
penalties_enabled: data.penalties_enabled ?? true,
show_amende_score: data.show_amende_score ?? true,
points_enabled: data.points_enabled ?? true,
points_separated: data.points_separated ?? true,
};
} catch {
return { penalties_enabled: true, points_enabled: true };
return { penalties_enabled: true, show_amende_score: true, points_enabled: true, points_separated: true };
}
};
@@ -44,7 +44,7 @@ export default function OrderHistoryScreen() {
const [orders, setOrders] = useState<CompletedOrder[]>([]);
const [stats, setStats] = useState<ClientStats | null>(null);
const [penalties, setPenalties] = useState<PenaltyInfo | null>(null);
const [appSettings, setAppSettings] = useState<PublicSettings>({ penalties_enabled: true, points_enabled: true });
const [appSettings, setAppSettings] = useState<PublicSettings>({ penalties_enabled: true, show_amende_score: true, points_enabled: true, points_separated: true });
const [loading, setLoading] = useState(true);
const [refreshing, setRefreshing] = useState(false);
@@ -245,6 +245,7 @@ export default function OrderHistoryScreen() {
<Text style={styles.statLabel}>Commandes</Text>
</View>
{appSettings.points_enabled && (
appSettings.points_separated ? (
<>
<View style={[styles.statCard, shadows.sm]}>
<Ionicons
@@ -286,10 +287,25 @@ export default function OrderHistoryScreen() {
</Text>
</View>
</>
) : (
<View style={[styles.statCard, shadows.sm]}>
<Ionicons
name="trophy-outline"
size={24}
color={colors.warning}
/>
<Text style={styles.statValue}>
{stats?.points || 0}
</Text>
<Text style={styles.statLabel}>
Points
</Text>
</View>
)
)}
</View>
{appSettings.penalties_enabled && penaltyCount > 0 && (
{appSettings.show_amende_score && penaltyCount > 0 && (
<View
style={[
styles.penaltyBanner,