chore: fix
This commit is contained in:
@@ -663,10 +663,15 @@ export const deleteCategoryAdmin = async (
|
|||||||
|
|
||||||
export interface AppSettings {
|
export interface AppSettings {
|
||||||
penalties_enabled: boolean;
|
penalties_enabled: boolean;
|
||||||
|
show_amende_score: boolean;
|
||||||
points_enabled: boolean;
|
points_enabled: boolean;
|
||||||
points_categories_weed: string[];
|
points_categories_weed: string[];
|
||||||
points_categories_zipette: string[];
|
points_categories_zipette: string[];
|
||||||
points_separated: boolean;
|
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 }> => {
|
export const getSettings = async (): Promise<{ success: boolean; settings?: AppSettings; error?: string }> => {
|
||||||
|
|||||||
@@ -346,7 +346,9 @@ export const getAllAlerts = async (): Promise<{
|
|||||||
|
|
||||||
export interface PublicSettings {
|
export interface PublicSettings {
|
||||||
penalties_enabled: boolean;
|
penalties_enabled: boolean;
|
||||||
|
show_amende_score: boolean;
|
||||||
points_enabled: boolean;
|
points_enabled: boolean;
|
||||||
|
points_separated: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getPublicSettings = async (): Promise<PublicSettings> => {
|
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`);
|
const { data } = await apiClient.get(`http://5.181.0.112/api/v1/app-settings`);
|
||||||
return {
|
return {
|
||||||
penalties_enabled: data.penalties_enabled ?? true,
|
penalties_enabled: data.penalties_enabled ?? true,
|
||||||
|
show_amende_score: data.show_amende_score ?? true,
|
||||||
points_enabled: data.points_enabled ?? true,
|
points_enabled: data.points_enabled ?? true,
|
||||||
|
points_separated: data.points_separated ?? true,
|
||||||
};
|
};
|
||||||
} catch {
|
} 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,
|
Switch,
|
||||||
TouchableOpacity,
|
TouchableOpacity,
|
||||||
ActivityIndicator,
|
ActivityIndicator,
|
||||||
|
TextInput,
|
||||||
} 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";
|
||||||
@@ -26,10 +27,15 @@ export default function SettingsScreen() {
|
|||||||
const [saving, setSaving] = useState(false);
|
const [saving, setSaving] = useState(false);
|
||||||
const [settings, setSettings] = useState<AppSettings>({
|
const [settings, setSettings] = useState<AppSettings>({
|
||||||
penalties_enabled: true,
|
penalties_enabled: true,
|
||||||
|
show_amende_score: true,
|
||||||
points_enabled: true,
|
points_enabled: true,
|
||||||
points_categories_weed: [],
|
points_categories_weed: [],
|
||||||
points_categories_zipette: [],
|
points_categories_zipette: [],
|
||||||
points_separated: true,
|
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[]>([]);
|
const [categories, setCategories] = useState<Category[]>([]);
|
||||||
|
|
||||||
@@ -142,6 +148,31 @@ export default function SettingsScreen() {
|
|||||||
paddingHorizontal: spacing.l,
|
paddingHorizontal: spacing.l,
|
||||||
paddingBottom: spacing.m,
|
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: {
|
saveButton: {
|
||||||
backgroundColor: colors.accent,
|
backgroundColor: colors.accent,
|
||||||
borderRadius: borderRadius.lg,
|
borderRadius: borderRadius.lg,
|
||||||
@@ -188,6 +219,22 @@ export default function SettingsScreen() {
|
|||||||
thumbColor="#fff"
|
thumbColor="#fff"
|
||||||
/>
|
/>
|
||||||
</View>
|
</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>
|
</View>
|
||||||
|
|
||||||
{/* Système de points */}
|
{/* Système de points */}
|
||||||
@@ -324,6 +371,79 @@ export default function SettingsScreen() {
|
|||||||
)}
|
)}
|
||||||
</View>
|
</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
|
<TouchableOpacity
|
||||||
style={s.saveButton}
|
style={s.saveButton}
|
||||||
onPress={handleSave}
|
onPress={handleSave}
|
||||||
|
|||||||
@@ -19,7 +19,9 @@ export default function UsersScreen() {
|
|||||||
const [refreshing, setRefreshing] = useState(false);
|
const [refreshing, setRefreshing] = useState(false);
|
||||||
const [appSettings, setAppSettings] = useState<PublicSettings>({
|
const [appSettings, setAppSettings] = useState<PublicSettings>({
|
||||||
penalties_enabled: true,
|
penalties_enabled: true,
|
||||||
|
show_amende_score: true,
|
||||||
points_enabled: true,
|
points_enabled: true,
|
||||||
|
points_separated: true,
|
||||||
});
|
});
|
||||||
const [penaltyModal, setPenaltyModal] = useState<{
|
const [penaltyModal, setPenaltyModal] = useState<{
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
@@ -145,22 +147,31 @@ export default function UsersScreen() {
|
|||||||
</Text>
|
</Text>
|
||||||
<View style={styles.statsRow}>
|
<View style={styles.statsRow}>
|
||||||
{appSettings.points_enabled && (
|
{appSettings.points_enabled && (
|
||||||
<>
|
appSettings.points_separated ? (
|
||||||
|
<>
|
||||||
|
<View style={styles.stat}>
|
||||||
|
<Text style={[styles.statValue, { color: colors.success }]}>
|
||||||
|
{item.point}
|
||||||
|
</Text>
|
||||||
|
<Text style={styles.statLabel}>Points</Text>
|
||||||
|
</View>
|
||||||
|
<View style={styles.stat}>
|
||||||
|
<Text style={[styles.statValue, { color: colors.info }]}>
|
||||||
|
{item.points_zipette}
|
||||||
|
</Text>
|
||||||
|
<Text style={styles.statLabel}>Zipette</Text>
|
||||||
|
</View>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
<View style={styles.stat}>
|
<View style={styles.stat}>
|
||||||
<Text style={[styles.statValue, { color: colors.success }]}>
|
<Text style={[styles.statValue, { color: colors.success }]}>
|
||||||
{item.point}
|
{item.point}
|
||||||
</Text>
|
</Text>
|
||||||
<Text style={styles.statLabel}>Points</Text>
|
<Text style={styles.statLabel}>Points</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.stat}>
|
)
|
||||||
<Text style={[styles.statValue, { color: colors.info }]}>
|
|
||||||
{item.points_zipette}
|
|
||||||
</Text>
|
|
||||||
<Text style={styles.statLabel}>Zipette</Text>
|
|
||||||
</View>
|
|
||||||
</>
|
|
||||||
)}
|
)}
|
||||||
{appSettings.penalties_enabled && (
|
{appSettings.show_amende_score && (
|
||||||
<View style={styles.stat}>
|
<View style={styles.stat}>
|
||||||
<Text style={[styles.statValue, { color: colors.warning }]}>
|
<Text style={[styles.statValue, { color: colors.warning }]}>
|
||||||
{item.amende}
|
{item.amende}
|
||||||
|
|||||||
@@ -710,7 +710,9 @@ export const markNotificationsRead = async (): Promise<{
|
|||||||
|
|
||||||
export interface PublicSettings {
|
export interface PublicSettings {
|
||||||
penalties_enabled: boolean;
|
penalties_enabled: boolean;
|
||||||
|
show_amende_score: boolean;
|
||||||
points_enabled: boolean;
|
points_enabled: boolean;
|
||||||
|
points_separated: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getPublicSettings = async (): Promise<PublicSettings> => {
|
export const getPublicSettings = async (): Promise<PublicSettings> => {
|
||||||
@@ -718,10 +720,12 @@ export const getPublicSettings = async (): Promise<PublicSettings> => {
|
|||||||
const { data } = await apiClient.get(`${V1}/app-settings`);
|
const { data } = await apiClient.get(`${V1}/app-settings`);
|
||||||
return {
|
return {
|
||||||
penalties_enabled: data.penalties_enabled ?? true,
|
penalties_enabled: data.penalties_enabled ?? true,
|
||||||
|
show_amende_score: data.show_amende_score ?? true,
|
||||||
points_enabled: data.points_enabled ?? true,
|
points_enabled: data.points_enabled ?? true,
|
||||||
|
points_separated: data.points_separated ?? true,
|
||||||
};
|
};
|
||||||
} catch {
|
} 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 [orders, setOrders] = useState<CompletedOrder[]>([]);
|
||||||
const [stats, setStats] = useState<ClientStats | null>(null);
|
const [stats, setStats] = useState<ClientStats | null>(null);
|
||||||
const [penalties, setPenalties] = useState<PenaltyInfo | 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 [loading, setLoading] = useState(true);
|
||||||
const [refreshing, setRefreshing] = useState(false);
|
const [refreshing, setRefreshing] = useState(false);
|
||||||
|
|
||||||
@@ -245,33 +245,49 @@ export default function OrderHistoryScreen() {
|
|||||||
<Text style={styles.statLabel}>Commandes</Text>
|
<Text style={styles.statLabel}>Commandes</Text>
|
||||||
</View>
|
</View>
|
||||||
{appSettings.points_enabled && (
|
{appSettings.points_enabled && (
|
||||||
<>
|
appSettings.points_separated ? (
|
||||||
<View style={[styles.statCard, shadows.sm]}>
|
<>
|
||||||
<Ionicons
|
<View style={[styles.statCard, shadows.sm]}>
|
||||||
name="leaf-outline"
|
<Ionicons
|
||||||
size={24}
|
name="leaf-outline"
|
||||||
color={colors.categoryWeedHash}
|
size={24}
|
||||||
/>
|
color={colors.categoryWeedHash}
|
||||||
<Text style={styles.statValue}>
|
/>
|
||||||
{stats?.points || 0}
|
<Text style={styles.statValue}>
|
||||||
</Text>
|
{stats?.points || 0}
|
||||||
<Text style={styles.statLabel}>
|
</Text>
|
||||||
Pts Weed/Hash
|
<Text style={styles.statLabel}>
|
||||||
</Text>
|
Pts Weed/Hash
|
||||||
</View>
|
</Text>
|
||||||
<View style={[styles.statCard, shadows.sm]}>
|
</View>
|
||||||
<Ionicons
|
<View style={[styles.statCard, shadows.sm]}>
|
||||||
name="flash-outline"
|
<Ionicons
|
||||||
size={24}
|
name="flash-outline"
|
||||||
color={colors.info}
|
size={24}
|
||||||
/>
|
color={colors.info}
|
||||||
<Text style={styles.statValue}>
|
/>
|
||||||
{stats?.points_zipette || 0}
|
<Text style={styles.statValue}>
|
||||||
</Text>
|
{stats?.points_zipette || 0}
|
||||||
<Text style={styles.statLabel}>
|
</Text>
|
||||||
Pts Zipette
|
<Text style={styles.statLabel}>
|
||||||
</Text>
|
Pts Zipette
|
||||||
</View>
|
</Text>
|
||||||
|
</View>
|
||||||
|
<View style={[styles.statCard, shadows.sm]}>
|
||||||
|
<Ionicons
|
||||||
|
name="trophy-outline"
|
||||||
|
size={24}
|
||||||
|
color={colors.warning}
|
||||||
|
/>
|
||||||
|
<Text style={styles.statValue}>
|
||||||
|
{totalPoints}
|
||||||
|
</Text>
|
||||||
|
<Text style={styles.statLabel}>
|
||||||
|
Total Points
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
<View style={[styles.statCard, shadows.sm]}>
|
<View style={[styles.statCard, shadows.sm]}>
|
||||||
<Ionicons
|
<Ionicons
|
||||||
name="trophy-outline"
|
name="trophy-outline"
|
||||||
@@ -279,17 +295,17 @@ export default function OrderHistoryScreen() {
|
|||||||
color={colors.warning}
|
color={colors.warning}
|
||||||
/>
|
/>
|
||||||
<Text style={styles.statValue}>
|
<Text style={styles.statValue}>
|
||||||
{totalPoints}
|
{stats?.points || 0}
|
||||||
</Text>
|
</Text>
|
||||||
<Text style={styles.statLabel}>
|
<Text style={styles.statLabel}>
|
||||||
Total Points
|
Points
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
</>
|
)
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
{appSettings.penalties_enabled && penaltyCount > 0 && (
|
{appSettings.show_amende_score && penaltyCount > 0 && (
|
||||||
<View
|
<View
|
||||||
style={[
|
style={[
|
||||||
styles.penaltyBanner,
|
styles.penaltyBanner,
|
||||||
|
|||||||
Reference in New Issue
Block a user