This commit is contained in:
@@ -857,6 +857,7 @@ export interface Category {
|
|||||||
name: string;
|
name: string;
|
||||||
color: string;
|
color: string;
|
||||||
is_coming_soon: boolean;
|
is_coming_soon: boolean;
|
||||||
|
position: number;
|
||||||
created_at: string;
|
created_at: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -922,6 +923,20 @@ export const deleteCategoryAdmin = async (
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const reorderCategoriesAdmin = async (
|
||||||
|
ids: number[],
|
||||||
|
): Promise<{ success: boolean; error?: string }> => {
|
||||||
|
try {
|
||||||
|
await apiClient.put(`${V2}/admin/protected/categories/reorder`, { ids });
|
||||||
|
return { success: true };
|
||||||
|
} catch (error: any) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: error.response?.data?.error || "Erreur",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// ============================================
|
// ============================================
|
||||||
// PARAMÈTRES GLOBAUX
|
// PARAMÈTRES GLOBAUX
|
||||||
// ============================================
|
// ============================================
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ interface ThemeContextType {
|
|||||||
mode: ThemeMode;
|
mode: ThemeMode;
|
||||||
toggleTheme: () => void;
|
toggleTheme: () => void;
|
||||||
isDark: boolean;
|
isDark: boolean;
|
||||||
|
refreshColors: () => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const STORAGE_KEY = "@theme_mode";
|
const STORAGE_KEY = "@theme_mode";
|
||||||
@@ -71,6 +72,7 @@ export function ThemeProvider({ children }: { children: ReactNode }) {
|
|||||||
mode,
|
mode,
|
||||||
toggleTheme,
|
toggleTheme,
|
||||||
isDark: mode === "dark",
|
isDark: mode === "dark",
|
||||||
|
refreshColors: fetchAdminColors,
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import {
|
|||||||
createCategoryAdmin,
|
createCategoryAdmin,
|
||||||
updateCategoryAdmin,
|
updateCategoryAdmin,
|
||||||
deleteCategoryAdmin,
|
deleteCategoryAdmin,
|
||||||
|
reorderCategoriesAdmin,
|
||||||
} from "../../api/api_admin";
|
} from "../../api/api_admin";
|
||||||
import type { Category } from "../../api/api_admin";
|
import type { Category } from "../../api/api_admin";
|
||||||
import LoadingSpinner from "../../components/ui/LoadingSpinner";
|
import LoadingSpinner from "../../components/ui/LoadingSpinner";
|
||||||
@@ -47,6 +48,7 @@ export default function CategoriesScreen() {
|
|||||||
const [hexInput, setHexInput] = useState("#7c3aed");
|
const [hexInput, setHexInput] = useState("#7c3aed");
|
||||||
const [isComingSoon, setIsComingSoon] = useState(false);
|
const [isComingSoon, setIsComingSoon] = useState(false);
|
||||||
const [saving, setSaving] = useState(false);
|
const [saving, setSaving] = useState(false);
|
||||||
|
const [reordering, setReordering] = useState(false);
|
||||||
const { alert, showError, showSuccess, showConfirm, hideAlert } = useAlert();
|
const { alert, showError, showSuccess, showConfirm, hideAlert } = useAlert();
|
||||||
|
|
||||||
const load = useCallback(async () => {
|
const load = useCallback(async () => {
|
||||||
@@ -144,6 +146,17 @@ export default function CategoriesScreen() {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleMove = async (index: number, direction: "up" | "down") => {
|
||||||
|
const newList = [...categories];
|
||||||
|
const swapIndex = direction === "up" ? index - 1 : index + 1;
|
||||||
|
if (swapIndex < 0 || swapIndex >= newList.length) return;
|
||||||
|
[newList[index], newList[swapIndex]] = [newList[swapIndex], newList[index]];
|
||||||
|
setCategories(newList);
|
||||||
|
setReordering(true);
|
||||||
|
await reorderCategoriesAdmin(newList.map((c) => c.id));
|
||||||
|
setReordering(false);
|
||||||
|
};
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: { flex: 1, backgroundColor: colors.bgPrimary },
|
container: { flex: 1, backgroundColor: colors.bgPrimary },
|
||||||
header: {
|
header: {
|
||||||
@@ -189,6 +202,8 @@ export default function CategoriesScreen() {
|
|||||||
paddingVertical: 2,
|
paddingVertical: 2,
|
||||||
},
|
},
|
||||||
comingSoonBadgeText: { fontSize: fontSize.xs, color: colors.warning, fontWeight: "600" },
|
comingSoonBadgeText: { fontSize: fontSize.xs, color: colors.warning, fontWeight: "600" },
|
||||||
|
orderBtns: { flexDirection: "column", alignItems: "center", marginRight: spacing.s },
|
||||||
|
orderBtn: { padding: 2 },
|
||||||
actions: { flexDirection: "row", gap: spacing.s },
|
actions: { flexDirection: "row", gap: spacing.s },
|
||||||
actionBtn: { padding: 8 },
|
actionBtn: { padding: 8 },
|
||||||
overlay: {
|
overlay: {
|
||||||
@@ -297,9 +312,33 @@ export default function CategoriesScreen() {
|
|||||||
ListEmptyComponent={
|
ListEmptyComponent={
|
||||||
<Text style={styles.empty}>Aucune catégorie. Créez-en une !</Text>
|
<Text style={styles.empty}>Aucune catégorie. Créez-en une !</Text>
|
||||||
}
|
}
|
||||||
renderItem={({ item }) => (
|
renderItem={({ item, index }) => (
|
||||||
<Card>
|
<Card>
|
||||||
<View style={styles.row}>
|
<View style={styles.row}>
|
||||||
|
<View style={styles.orderBtns}>
|
||||||
|
<TouchableOpacity
|
||||||
|
onPress={() => handleMove(index, "up")}
|
||||||
|
disabled={index === 0 || reordering}
|
||||||
|
style={styles.orderBtn}
|
||||||
|
>
|
||||||
|
<Ionicons
|
||||||
|
name="chevron-up"
|
||||||
|
size={18}
|
||||||
|
color={index === 0 ? colors.textMuted : colors.textSecondary}
|
||||||
|
/>
|
||||||
|
</TouchableOpacity>
|
||||||
|
<TouchableOpacity
|
||||||
|
onPress={() => handleMove(index, "down")}
|
||||||
|
disabled={index === categories.length - 1 || reordering}
|
||||||
|
style={styles.orderBtn}
|
||||||
|
>
|
||||||
|
<Ionicons
|
||||||
|
name="chevron-down"
|
||||||
|
size={18}
|
||||||
|
color={index === categories.length - 1 ? colors.textMuted : colors.textSecondary}
|
||||||
|
/>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
<View style={styles.catLeft}>
|
<View style={styles.catLeft}>
|
||||||
<View
|
<View
|
||||||
style={[
|
style={[
|
||||||
|
|||||||
@@ -1156,7 +1156,7 @@ function CentralRewardSection({
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function SettingsScreen() {
|
export default function SettingsScreen() {
|
||||||
const { colors } = useTheme();
|
const { colors, refreshColors } = useTheme();
|
||||||
const { alert, showError, showSuccess, hideAlert } = useAlert();
|
const { alert, showError, showSuccess, hideAlert } = useAlert();
|
||||||
const navigation = useNavigation();
|
const navigation = useNavigation();
|
||||||
const { width: screenWidth } = useWindowDimensions();
|
const { width: screenWidth } = useWindowDimensions();
|
||||||
@@ -1366,6 +1366,7 @@ export default function SettingsScreen() {
|
|||||||
setSaving(false);
|
setSaving(false);
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
isDirty.current = false;
|
isDirty.current = false;
|
||||||
|
await refreshColors();
|
||||||
showSuccess("Succès", "Paramètres sauvegardés");
|
showSuccess("Succès", "Paramètres sauvegardés");
|
||||||
} else {
|
} else {
|
||||||
showError("Erreur", res.error || "Erreur lors de la sauvegarde");
|
showError("Erreur", res.error || "Erreur lors de la sauvegarde");
|
||||||
|
|||||||
Reference in New Issue
Block a user