From ab7d8929a8e6f4eabcfee39773b201e32969ecb9 Mon Sep 17 00:00:00 2001 From: Xor290 Date: Sat, 7 Mar 2026 17:59:34 +0100 Subject: [PATCH] chore: add comming soon category --- frontend-admin/src/api/api_admin.ts | 7 ++- .../src/screens/admin/CategoriesScreen.tsx | 51 +++++++++++++++++-- mobile/src/api/api.ts | 1 + mobile/src/screens/client/ProductsScreen.tsx | 28 +++++++++- 4 files changed, 81 insertions(+), 6 deletions(-) diff --git a/frontend-admin/src/api/api_admin.ts b/frontend-admin/src/api/api_admin.ts index 3533f99b..fd954514 100644 --- a/frontend-admin/src/api/api_admin.ts +++ b/frontend-admin/src/api/api_admin.ts @@ -591,6 +591,7 @@ export interface Category { id: number; name: string; color: string; + is_coming_soon: boolean; created_at: string; } @@ -606,11 +607,12 @@ export const getCategories = async (): Promise => { export const createCategoryAdmin = async ( name: string, color: string, + isComingSoon: boolean = false, ): Promise<{ success: boolean; category?: Category; error?: string }> => { try { const { data } = await apiClient.post( `${V2}/admin/protected/categories`, - { name, color }, + { name, color, is_coming_soon: isComingSoon }, ); return { success: true, category: data.category }; } catch (error: any) { @@ -625,11 +627,12 @@ export const updateCategoryAdmin = async ( id: number, name: string, color: string, + isComingSoon: boolean = false, ): Promise<{ success: boolean; category?: Category; error?: string }> => { try { const { data } = await apiClient.put( `${V2}/admin/protected/categories/${id}`, - { name, color }, + { name, color, is_coming_soon: isComingSoon }, ); return { success: true, category: data.category }; } catch (error: any) { diff --git a/frontend-admin/src/screens/admin/CategoriesScreen.tsx b/frontend-admin/src/screens/admin/CategoriesScreen.tsx index 6bb6fad2..5104a39a 100644 --- a/frontend-admin/src/screens/admin/CategoriesScreen.tsx +++ b/frontend-admin/src/screens/admin/CategoriesScreen.tsx @@ -10,6 +10,7 @@ import { KeyboardAvoidingView, Platform, ScrollView, + Switch, } from "react-native"; import { Ionicons } from "@expo/vector-icons"; import { spacing, fontSize, borderRadius } from "../../theme"; @@ -44,6 +45,7 @@ export default function CategoriesScreen() { const [name, setName] = useState(""); const [color, setColor] = useState("#7c3aed"); const [hexInput, setHexInput] = useState("#7c3aed"); + const [isComingSoon, setIsComingSoon] = useState(false); const [saving, setSaving] = useState(false); const { alert, showError, showSuccess, showConfirm, hideAlert } = useAlert(); @@ -74,6 +76,7 @@ export default function CategoriesScreen() { setEditingCategory(null); setName(""); selectColor("#7c3aed"); + setIsComingSoon(false); setModalVisible(true); }; @@ -81,12 +84,14 @@ export default function CategoriesScreen() { setEditingCategory(cat); setName(cat.name); selectColor(cat.color || "#7c3aed"); + setIsComingSoon(cat.is_coming_soon || false); setModalVisible(true); }; const closeModal = () => { setModalVisible(false); setName(""); + setIsComingSoon(false); setEditingCategory(null); }; @@ -102,7 +107,7 @@ export default function CategoriesScreen() { } setSaving(true); if (editingCategory) { - const res = await updateCategoryAdmin(editingCategory.id, trimmed, color); + const res = await updateCategoryAdmin(editingCategory.id, trimmed, color, isComingSoon); if (res.success) { showSuccess("Succès", "Catégorie modifiée"); closeModal(); @@ -111,7 +116,7 @@ export default function CategoriesScreen() { showError("Erreur", res.error || "Erreur"); } } else { - const res = await createCategoryAdmin(trimmed, color); + const res = await createCategoryAdmin(trimmed, color, isComingSoon); if (res.success) { showSuccess("Succès", "Catégorie créée"); closeModal(); @@ -175,6 +180,15 @@ export default function CategoriesScreen() { textTransform: "capitalize", }, catDate: { fontSize: fontSize.xs, color: colors.textSecondary, marginTop: 2 }, + comingSoonBadge: { + backgroundColor: colors.warning + "33", + borderWidth: 1, + borderColor: colors.warning, + borderRadius: borderRadius.sm, + paddingHorizontal: 6, + paddingVertical: 2, + }, + comingSoonBadgeText: { fontSize: fontSize.xs, color: colors.warning, fontWeight: "600" }, actions: { flexDirection: "row", gap: spacing.s }, actionBtn: { padding: 8 }, overlay: { @@ -230,6 +244,15 @@ export default function CategoriesScreen() { borderRadius: borderRadius.sm, borderWidth: 2, }, + comingSoonRow: { + flexDirection: "row", + alignItems: "center", + justifyContent: "space-between", + paddingVertical: spacing.s, + borderTopWidth: 1, + borderTopColor: colors.border, + }, + comingSoonHint: { fontSize: fontSize.xs, color: colors.textMuted, marginTop: 2 }, modalBtns: { flexDirection: "row", gap: spacing.s }, cancelBtn: { flex: 1, @@ -285,7 +308,14 @@ export default function CategoriesScreen() { ]} /> - {item.name} + + {item.name} + {item.is_coming_soon && ( + + Prochainement + + )} + Créée le{" "} {new Date(item.created_at).toLocaleDateString("fr-FR")} @@ -378,6 +408,21 @@ export default function CategoriesScreen() { + + + Prochainement + + Affiche un message d'attente aux clients + + + + + Annuler diff --git a/mobile/src/api/api.ts b/mobile/src/api/api.ts index ed1e4de4..946204d7 100644 --- a/mobile/src/api/api.ts +++ b/mobile/src/api/api.ts @@ -117,6 +117,7 @@ export interface Category { id: number; name: string; color: string; + is_coming_soon: boolean; created_at: string; } diff --git a/mobile/src/screens/client/ProductsScreen.tsx b/mobile/src/screens/client/ProductsScreen.tsx index 77a0fdf2..dbd1de10 100644 --- a/mobile/src/screens/client/ProductsScreen.tsx +++ b/mobile/src/screens/client/ProductsScreen.tsx @@ -164,6 +164,13 @@ export default function ProductsScreen() { paddingBottom: 96, pointerEvents: "none", }, + comingSoonContent: { + flex: 1, + justifyContent: "center", + alignItems: "center", + padding: spacing.xl, + gap: spacing.m, + }, comingSoonText: { fontSize: 36, color: "#8E8FE8", @@ -174,10 +181,18 @@ export default function ProductsScreen() { textShadowOffset: { width: 0, height: 0 }, textShadowRadius: 18, }, + comingSoonDesc: { + fontSize: fontSize.md, + color: "rgba(142, 143, 232, 0.7)", + textAlign: "center", + }, }), [colors], ); + const selectedCategoryObj = categories.find((c) => c.name === selectedCategory); + const isSelectedComingSoon = selectedCategoryObj?.is_coming_soon ?? false; + if (loading && !refreshing) { return ; } @@ -215,7 +230,18 @@ export default function ProductsScreen() { {selectedCategory === "tous" ? "Tous les produits" : selectedCategory} - {error ? ( + {isSelectedComingSoon ? ( + + + Prochainement + + + Les produits de cette catégorie arrivent bientôt ! + + + ) : error ? ( {error}