chore: build
Omnex Plateform App - EAS Build / build (push) Canceled after 1h41m41s
Omnex Plateform Client - EAS Build / build (push) Failing after 14m25s

This commit is contained in:
Xor290
2026-08-25 15:15:45 +02:00
parent edc0b32ae0
commit 5b3c30143d
9 changed files with 124 additions and 94 deletions
+12 -8
View File
@@ -1,4 +1,5 @@
import apiClient from "./client"; import apiClient from "./client";
import { API_BASE_URL } from "./client";
import type { import type {
AuthResponse, AuthResponse,
ClientResponse, ClientResponse,
@@ -9,9 +10,9 @@ import type {
Alert, Alert,
} from "./types"; } from "./types";
const V2 = "/api/v2"; const V2 = `${API_BASE_URL}/api/v2`;
const CABINE_URL = "/api/v1/cabine"; const CABINE_URL = `${API_BASE_URL}/api/v1/cabine`;
const V1_PUBLIC = "/api/v1"; const V1_PUBLIC = `${API_BASE_URL}/api/v1`;
export const loginAdmin = async ( export const loginAdmin = async (
username: string, username: string,
@@ -172,10 +173,12 @@ export const resetAdminStats = async (
); );
return data; return data;
}; };
// ============================================
// STATISTIQUES MENSUELLES (jour par jour)
// ============================================
export interface MonthlyDayStat { export interface MonthlyDayStat {
day: string; day: string; // "2026-06-05"
label: string; label: string; // "05/06"
count: number; count: number;
revenue: number; revenue: number;
quantity: number; quantity: number;
@@ -186,7 +189,7 @@ export interface MonthlyStatsSummary {
total_quantity: number; total_quantity: number;
} }
export interface MonthlyStats { export interface MonthlyStats {
month: string; month: string; // "2026-06"
summary: MonthlyStatsSummary; summary: MonthlyStatsSummary;
by_day: MonthlyDayStat[]; by_day: MonthlyDayStat[];
} }
@@ -798,6 +801,7 @@ export const getClientCancelledOrders = async (
} }
}; };
// ============================================
// AMENDES & POINTS CLIENT (Admin) // AMENDES & POINTS CLIENT (Admin)
// ============================================ // ============================================
@@ -1105,6 +1109,7 @@ export interface PointsTier {
export interface RewardCategoryConfig { export interface RewardCategoryConfig {
category: string; category: string;
type: "free_product" | "half_price_product";
all_products: boolean; all_products: boolean;
product_ids: number[]; product_ids: number[];
} }
@@ -1117,7 +1122,6 @@ export interface RewardItem {
export interface PointsReward { export interface PointsReward {
threshold: number; threshold: number;
type: "free_product" | "half_price_product" | "custom";
description: string; description: string;
category_configs: RewardCategoryConfig[]; category_configs: RewardCategoryConfig[];
reward_items: RewardItem[]; reward_items: RewardItem[];
+7 -5
View File
@@ -1,4 +1,5 @@
import apiClient from "./client"; import apiClient from "./client";
import { API_BASE_URL } from "./client";
//@ts //@ts
import type { import type {
@@ -8,8 +9,8 @@ import type {
Alert, Alert,
} from "./types"; } from "./types";
const API = "/api/v1/cabine"; const API = `${API_BASE_URL}/api/v1/cabine`;
const V2 = "/api/v2"; const V2 = `${API_BASE_URL}/api/v2`;
export const getCommandItems = async (commandId: number) => { export const getCommandItems = async (commandId: number) => {
const { data } = await apiClient.get(`${API}/commands/${commandId}/items`); const { data } = await apiClient.get(`${API}/commands/${commandId}/items`);
@@ -163,7 +164,6 @@ export const getDeliverymanLocationForCommand = async (commandId: number) => {
// ============================================ // ============================================
// LIVREURS // LIVREURS
// ============================================
const parseStatus = (status: any): "available" | "busy" | "offline" => { const parseStatus = (status: any): "available" | "busy" | "offline" => {
if (!status) return "offline"; if (!status) return "offline";
@@ -365,7 +365,9 @@ export const markCabineNotificationsRead = async (): Promise<void> => {
export const getPublicSettings = async (): Promise<PublicSettings> => { export const getPublicSettings = async (): Promise<PublicSettings> => {
try { try {
const { data } = await apiClient.get("/api/v1/app-settings"); const { data } = await apiClient.get(
`${API_BASE_URL}/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, show_amende_score: data.show_amende_score ?? true,
@@ -458,7 +460,7 @@ export const getCabineAllClients = async (): Promise<any[]> => {
// TELEGRAM — CABINE // TELEGRAM — CABINE
// ============================================ // ============================================
const CABINE_API = "/api/v1/cabine"; const CABINE_API = `${API_BASE_URL}/api/v1/cabine`;
export const getCabineTelegramStatus = async (): Promise<{ export const getCabineTelegramStatus = async (): Promise<{
linked: boolean; linked: boolean;
+2 -1
View File
@@ -1,4 +1,5 @@
import apiClient from "./client"; import apiClient from "./client";
import { API_BASE_URL } from "./client";
import type { import type {
DeliveryStatus, DeliveryStatus,
QueueInfo, QueueInfo,
@@ -7,7 +8,7 @@ import type {
Alert, Alert,
} from "./types"; } from "./types";
const API = "/api/v1/livreur"; const API = `${API_BASE_URL}/api/v1/livreur`;
export const getMyStatus = async (): Promise<{ export const getMyStatus = async (): Promise<{
success: boolean; success: boolean;
@@ -686,14 +686,13 @@ function TiersSection({
const REWARD_ACCENT = "#f59e0b"; const REWARD_ACCENT = "#f59e0b";
const REWARD_TYPES: { value: PointsReward["type"]; label: string; icon: string }[] = [ const REWARD_TYPES: { value: RewardCategoryConfig["type"]; label: string; icon: string }[] = [
{ value: "free_product", label: "Produit offert", icon: "gift-outline" }, { value: "free_product", label: "Produit offert", icon: "gift-outline" },
{ value: "half_price_product", label: "Produit à -50%", icon: "pricetag-outline" }, { value: "half_price_product", label: "Produit à -50%", icon: "pricetag-outline" },
]; ];
const EMPTY_REWARD: PointsReward = { const EMPTY_REWARD: PointsReward = {
threshold: 20, threshold: 20,
type: "free_product",
description: "", description: "",
category_configs: [], category_configs: [],
reward_items: [], reward_items: [],
@@ -822,7 +821,7 @@ function CentralRewardSection({
const getCatConfig = (catName: string): RewardCategoryConfig => const getCatConfig = (catName: string): RewardCategoryConfig =>
r.category_configs.find((c) => c.category === catName) ?? r.category_configs.find((c) => c.category === catName) ??
{ category: catName, all_products: true, product_ids: [] }; { category: catName, type: "free_product", all_products: true, product_ids: [] };
const isCatSelected = (catName: string) => const isCatSelected = (catName: string) =>
r.category_configs.some((c) => c.category === catName); r.category_configs.some((c) => c.category === catName);
@@ -831,7 +830,7 @@ function CentralRewardSection({
if (isCatSelected(catName)) { if (isCatSelected(catName)) {
update({ category_configs: r.category_configs.filter((c) => c.category !== catName) }); update({ category_configs: r.category_configs.filter((c) => c.category !== catName) });
} else { } else {
update({ category_configs: [...r.category_configs, { category: catName, all_products: true, product_ids: [] }] }); update({ category_configs: [...r.category_configs, { category: catName, type: "free_product", all_products: true, product_ids: [] }] });
} }
}; };
@@ -894,34 +893,6 @@ function CentralRewardSection({
</View> </View>
</View> </View>
{/* Type */}
<View>
<Text style={[s.rowLabel, { marginBottom: spacing.s }]}>Type de récompense</Text>
<View style={{ flexDirection: "row", flexWrap: "wrap", gap: spacing.s }}>
{REWARD_TYPES.map((rt) => {
const sel = r.type === rt.value;
return (
<TouchableOpacity
key={rt.value}
onPress={() => update({ type: rt.value })}
style={{
flexDirection: "row", alignItems: "center", gap: spacing.xs,
paddingHorizontal: spacing.m, paddingVertical: spacing.s,
borderRadius: borderRadius.sm, borderWidth: 1.5,
borderColor: sel ? REWARD_ACCENT : colors.border,
backgroundColor: sel ? REWARD_ACCENT + "20" : "transparent",
}}
>
<Ionicons name={rt.icon as any} size={14} color={sel ? REWARD_ACCENT : colors.textMuted} />
<Text style={{ fontSize: 13, fontWeight: sel ? "700" : "400", color: sel ? REWARD_ACCENT : colors.textMuted }}>
{rt.label}
</Text>
</TouchableOpacity>
);
})}
</View>
</View>
{/* Description */} {/* Description */}
<View> <View>
<Text style={[s.rowLabel, { marginBottom: spacing.xs }]}>Description affichée au client</Text> <Text style={[s.rowLabel, { marginBottom: spacing.xs }]}>Description affichée au client</Text>
@@ -935,12 +906,12 @@ function CentralRewardSection({
/> />
</View> </View>
{/* Produits récompense — uniquement pour le type "Produit offert" */} {/* Produits récompense — proposés au client selon le type choisi
{r.type === "free_product" && ( pour la catégorie de chaque produit (voir "Catégories éligibles" ci-dessous) */}
<View> <View>
<Text style={[s.rowLabel, { marginBottom: spacing.xs }]}>Produits ajoutés au panier</Text> <Text style={[s.rowLabel, { marginBottom: spacing.xs }]}>Produits ajoutés au panier</Text>
<Text style={[s.rowDesc, { marginBottom: spacing.m }]}> <Text style={[s.rowDesc, { marginBottom: spacing.m }]}>
Quand le client réclame sa récompense, ces produits sont automatiquement ajoutés à son panier (gratuits). Il doit commander au moins un produit normal. Quand le client réclame sa récompense, ces produits sont automatiquement ajoutés à son panier gratuits ou à -50% selon le type configuré pour la catégorie du produit. Il doit commander au moins un produit normal.
</Text> </Text>
<View style={{ gap: spacing.s }}> <View style={{ gap: spacing.s }}>
{r.reward_items.map((item, idx) => { {r.reward_items.map((item, idx) => {
@@ -1062,14 +1033,14 @@ function CentralRewardSection({
)} )}
</View> </View>
</View> </View>
)}
{/* Catégories éligibles — uniquement pour le type "Produit à -50%" */} {/* Catégories éligibles — chaque catégorie choisit son propre type
{r.type === "half_price_product" && ( (produit offert ou -50%), qui s'applique aux produits récompense
de cette catégorie configurés ci-dessus */}
<View> <View>
<Text style={[s.rowLabel, { marginBottom: spacing.xs }]}>Catégories éligibles à -50%</Text> <Text style={[s.rowLabel, { marginBottom: spacing.xs }]}>Catégories éligibles</Text>
<Text style={[s.rowDesc, { marginBottom: spacing.m }]}> <Text style={[s.rowDesc, { marginBottom: spacing.m }]}>
Sélectionnez les catégories, puis pour chacune choisissez tous les produits ou une sélection. Sélectionnez les catégories, choisissez le type de récompense pour chacune, puis tous les produits ou une sélection.
</Text> </Text>
{allCategories.length === 0 ? ( {allCategories.length === 0 ? (
<Text style={[s.hint, { paddingHorizontal: 0 }]}>Aucune catégorie disponible</Text> <Text style={[s.hint, { paddingHorizontal: 0 }]}>Aucune catégorie disponible</Text>
@@ -1103,15 +1074,41 @@ function CentralRewardSection({
/> />
</TouchableOpacity> </TouchableOpacity>
{/* Sélecteur produits (visible si catégorie sélectionnée) */} {/* Type + sélecteur produits (visible si catégorie sélectionnée) */}
{selected && ( {selected && (
<CategoryProductPicker <View style={{ marginTop: spacing.s, paddingLeft: spacing.m, gap: spacing.s }}>
catConfig={getCatConfig(cat.name)} <View style={{ flexDirection: "row", flexWrap: "wrap", gap: spacing.xs }}>
products={productsByCategory[cat.name] ?? []} {REWARD_TYPES.map((rt) => {
onChange={updateCatConfig} const cfg = getCatConfig(cat.name);
colors={colors} const sel = (cfg.type || "free_product") === rt.value;
s={s} return (
/> <TouchableOpacity
key={rt.value}
onPress={() => updateCatConfig({ ...cfg, type: rt.value })}
style={{
flexDirection: "row", alignItems: "center", gap: 4,
paddingHorizontal: spacing.s, paddingVertical: 4,
borderRadius: borderRadius.sm, borderWidth: 1.5,
borderColor: sel ? REWARD_ACCENT : colors.border,
backgroundColor: sel ? REWARD_ACCENT + "22" : "transparent",
}}
>
<Ionicons name={rt.icon as any} size={12} color={sel ? REWARD_ACCENT : colors.textMuted} />
<Text style={{ fontSize: 12, fontWeight: sel ? "700" : "400", color: sel ? REWARD_ACCENT : colors.textMuted }}>
{rt.label}
</Text>
</TouchableOpacity>
);
})}
</View>
<CategoryProductPicker
catConfig={getCatConfig(cat.name)}
products={productsByCategory[cat.name] ?? []}
onChange={updateCatConfig}
colors={colors}
s={s}
/>
</View>
)} )}
</View> </View>
); );
@@ -1119,25 +1116,23 @@ function CentralRewardSection({
</View> </View>
)} )}
</View> </View>
)}
{/* Récapitulatif */} {/* Récapitulatif */}
{(r.category_configs.length > 0 || r.reward_items.filter((it) => it.product_id > 0).length > 0) && ( {(r.category_configs.length > 0 || r.reward_items.filter((it) => it.product_id > 0).length > 0) && (
<View style={{ backgroundColor: REWARD_ACCENT + "12", borderRadius: borderRadius.sm, borderLeftWidth: 3, borderLeftColor: REWARD_ACCENT, padding: spacing.m, gap: 4 }}> <View style={{ backgroundColor: REWARD_ACCENT + "12", borderRadius: borderRadius.sm, borderLeftWidth: 3, borderLeftColor: REWARD_ACCENT, padding: spacing.m, gap: 4 }}>
<Text style={{ fontSize: 13, fontWeight: "700", color: REWARD_ACCENT }}>Récapitulatif</Text> <Text style={{ fontSize: 13, fontWeight: "700", color: REWARD_ACCENT }}>Récapitulatif</Text>
<Text style={{ fontSize: 13, color: colors.textPrimary }}> <Text style={{ fontSize: 13, color: colors.textPrimary }}>
Dès <Text style={{ fontWeight: "700" }}>{r.threshold} pts</Text> par type {" "} Dès <Text style={{ fontWeight: "700" }}>{r.threshold} pts</Text> par type de points récompense débloquée
{REWARD_TYPES.find((x) => x.value === r.type)?.label}
</Text> </Text>
{r.description !== "" && ( {r.description !== "" && (
<Text style={{ fontSize: 12, color: colors.textMuted, fontStyle: "italic" }}>"{r.description}"</Text> <Text style={{ fontSize: 12, color: colors.textMuted, fontStyle: "italic" }}>"{r.description}"</Text>
)} )}
{r.type === "half_price_product" && r.category_configs.map((cfg) => ( {r.category_configs.map((cfg) => (
<Text key={cfg.category} style={{ fontSize: 12, color: colors.textSecondary }}> <Text key={cfg.category} style={{ fontSize: 12, color: colors.textSecondary }}>
Éligible à -50% : {cfg.category} {cfg.all_products ? "tous les produits" : `${cfg.product_ids.length} produit(s)`} {REWARD_TYPES.find((x) => x.value === (cfg.type || "free_product"))?.label} : {cfg.category} {cfg.all_products ? "tous les produits" : `${cfg.product_ids.length} produit(s)`}
</Text> </Text>
))} ))}
{r.type === "free_product" && r.reward_items.filter((it) => it.product_id > 0).map((it, idx) => { {r.reward_items.filter((it) => it.product_id > 0).map((it, idx) => {
const prod = Object.values(productsByCategory).flat().find((p) => p.id === it.product_id); const prod = Object.values(productsByCategory).flat().find((p) => p.id === it.product_id);
return ( return (
<View key={idx} style={{ flexDirection: "row", alignItems: "center", gap: 4 }}> <View key={idx} style={{ flexDirection: "row", alignItems: "center", gap: 4 }}>
@@ -715,7 +715,7 @@ export default function DashboardScreen() {
{prod.is_reward && ( {prod.is_reward && (
<View style={{ flexDirection: "row", alignItems: "center", gap: 2, backgroundColor: "rgba(245,158,11,0.15)", borderRadius: 4, paddingHorizontal: 4, paddingVertical: 1 }}> <View style={{ flexDirection: "row", alignItems: "center", gap: 2, backgroundColor: "rgba(245,158,11,0.15)", borderRadius: 4, paddingHorizontal: 4, paddingVertical: 1 }}>
<Ionicons name="gift-outline" size={10} color="#f59e0b" /> <Ionicons name="gift-outline" size={10} color="#f59e0b" />
<Text style={{ fontSize: 10, color: "#f59e0b", fontWeight: "700" }}>Offert</Text> <Text style={{ fontSize: 10, color: "#f59e0b", fontWeight: "700" }}>Récompense</Text>
</View> </View>
)} )}
</View> </View>
@@ -724,7 +724,7 @@ export default function DashboardScreen() {
</Text> </Text>
</View> </View>
<Text style={[styles.itemPrice, prod.is_reward ? { color: "#10b981" } : {}]}> <Text style={[styles.itemPrice, prod.is_reward ? { color: "#10b981" } : {}]}>
{prod.is_reward ? "Offert" : `${(prod.prix ?? 0).toFixed(2)}`} {prod.is_reward && (prod.prix ?? 0) === 0 ? "Offert" : `${(prod.prix ?? 0).toFixed(2)}`}
</Text> </Text>
</View> </View>
))} ))}
@@ -2018,7 +2018,7 @@ export default function DashboardScreen() {
{prod.is_reward && ( {prod.is_reward && (
<View style={{ flexDirection: "row", alignItems: "center", gap: 2, backgroundColor: "rgba(245,158,11,0.15)", borderRadius: 4, paddingHorizontal: 4, paddingVertical: 1 }}> <View style={{ flexDirection: "row", alignItems: "center", gap: 2, backgroundColor: "rgba(245,158,11,0.15)", borderRadius: 4, paddingHorizontal: 4, paddingVertical: 1 }}>
<Ionicons name="gift-outline" size={11} color="#f59e0b" /> <Ionicons name="gift-outline" size={11} color="#f59e0b" />
<Text style={{ fontSize: 11, color: "#f59e0b", fontWeight: "700" }}>Offert</Text> <Text style={{ fontSize: 11, color: "#f59e0b", fontWeight: "700" }}>Récompense</Text>
</View> </View>
)} )}
</View> </View>
@@ -2027,7 +2027,7 @@ export default function DashboardScreen() {
</Text> </Text>
</View> </View>
<Text style={[styles.detailProductPrice, prod.is_reward ? { color: "#10b981" } : {}]}> <Text style={[styles.detailProductPrice, prod.is_reward ? { color: "#10b981" } : {}]}>
{prod.is_reward ? "Offert" : `${(prod.prix ?? 0).toFixed(2)}`} {prod.is_reward && (prod.prix ?? 0) === 0 ? "Offert" : `${(prod.prix ?? 0).toFixed(2)}`}
</Text> </Text>
</View> </View>
))} ))}
+10 -9
View File
@@ -1,4 +1,5 @@
import apiClient from "./client"; import apiClient from "./client";
import { API_BASE_URL } from "./client";
import type { import type {
ConfirmReceptionResponse, ConfirmReceptionResponse,
CheckoutCartResponse, CheckoutCartResponse,
@@ -12,7 +13,7 @@ import type {
import { getToken } from "../auth/tokenStorage"; import { getToken } from "../auth/tokenStorage";
import { extractUsernameFromToken } from "../auth/jwtUtils"; import { extractUsernameFromToken } from "../auth/jwtUtils";
const V1 = "/api/v1"; const V1 = `${API_BASE_URL}/api/v1`;
export const getJwtUsername = async (): Promise<string | null> => { export const getJwtUsername = async (): Promise<string | null> => {
const token = await getToken(); const token = await getToken();
@@ -359,19 +360,18 @@ export const checkoutCart = async (
price_currency: data.price_currency, price_currency: data.price_currency,
}; };
} catch (error: any) { } catch (error: any) {
const errMsg: string = error.response?.data?.error || "Erreur serveur"; const data = error.response?.data;
if (errMsg.startsWith("Adresse invalide ")) { if (data?.corrected_address) {
const suggested = errMsg.replace("Adresse invalide ", "").trim();
return { return {
success: false, success: false,
invalid_address: true, invalid_address: true,
suggested_address: suggested, suggested_address: data.corrected_address,
message: errMsg, message: data.error || "Adresse non reconnue",
}; };
} }
return { return {
success: false, success: false,
message: errMsg, message: data?.error || "Erreur serveur",
}; };
} }
}; };
@@ -529,7 +529,6 @@ export const getOrdersWithTracking = async () => {
// ============================================ // ============================================
// HISTORY // HISTORY
// ============================================
export const getMyCompletedOrders = async (): Promise<HistoryResponse> => { export const getMyCompletedOrders = async (): Promise<HistoryResponse> => {
try { try {
@@ -661,6 +660,7 @@ export const updateMyProfile = async (fields: {
} }
}; };
// ============================================
// ORDER DETAILS // ORDER DETAILS
// ============================================ // ============================================
@@ -963,6 +963,7 @@ export const toggle2FA = async (
export type RewardCategoryConfig = { export type RewardCategoryConfig = {
category: string; category: string;
type: "free_product" | "half_price_product";
all_products: boolean; all_products: boolean;
product_ids: number[]; product_ids: number[];
product_names: string[]; product_names: string[];
@@ -974,6 +975,7 @@ export type RewardItemConfig = {
product_name: string; product_name: string;
quantity: number; quantity: number;
price: number; price: number;
type: "free_product" | "half_price_product";
}; };
export type PointsPoolInfo = { export type PointsPoolInfo = {
@@ -989,7 +991,6 @@ export type PointsPoolInfo = {
export type PointsRewardConfig = { export type PointsRewardConfig = {
threshold: number; threshold: number;
type: string;
description: string; description: string;
reward_items: RewardItemConfig[]; reward_items: RewardItemConfig[];
}; };
+1 -1
View File
@@ -10,7 +10,7 @@ export interface ApiResponse {
token_type?: string; token_type?: string;
expires_in?: number; expires_in?: number;
user?: UserResponse; user?: UserResponse;
[key: string]: any; [key: string]: any; // Pour les champs additionnels
} }
/** /**
@@ -146,7 +146,7 @@ export default function OrderHistoryScreen() {
if (res.success) { if (res.success) {
const text = const text =
res.product_added && res.product_name res.product_added && res.product_name
? `🎁 ${res.product_name} ajouté à votre panier ! Commandez au moins un produit pour en profiter.` ? `${res.product_name} ajouté à votre panier ! Commandez au moins un produit pour en profiter.`
: res.description || "Récompense réclamée !"; : res.description || "Récompense réclamée !";
setClaimFeedback({ pool: poolKey, type: "success", text }); setClaimFeedback({ pool: poolKey, type: "success", text });
getMyPointsRewards().then((r) => { getMyPointsRewards().then((r) => {
@@ -882,16 +882,34 @@ export default function OrderHistoryScreen() {
: `Encore ${remaining} pts pour une récompense`} : `Encore ${remaining} pts pour une récompense`}
</Text> </Text>
{feedback && ( {feedback && (
<Text <View
style={ style={{
feedback.type === flexDirection:
"success" "row",
? styles.feedbackSuccess alignItems:
: styles.feedbackError "center",
} gap: 4,
}}
> >
{feedback.text} {feedback.type ===
</Text> "success" && (
<Ionicons
name="gift-outline"
size={12}
color="#10b981"
/>
)}
<Text
style={
feedback.type ===
"success"
? styles.feedbackSuccess
: styles.feedbackError
}
>
{feedback.text}
</Text>
</View>
)} )}
{pool.rewards_available > 0 && ( {pool.rewards_available > 0 && (
<TouchableOpacity <TouchableOpacity
@@ -1132,11 +1150,18 @@ export default function OrderHistoryScreen() {
</Text> </Text>
)} )}
</View> </View>
{item.price > 0 && ( {item.type ===
"half_price_product" ? (
<Text <Text
style={styles.pickerItemPrice} style={styles.pickerItemPrice}
> >
{item.price} -50% · {item.price}
</Text>
) : (
<Text
style={styles.pickerItemPrice}
>
Offert
</Text> </Text>
)} )}
<Ionicons <Ionicons
@@ -28,6 +28,8 @@ import { spacing, fontSize } from "../../theme";
import { useTheme } from "../../context/ThemeContext"; import { useTheme } from "../../context/ThemeContext";
import type { ClientStackParamList } from "../../navigation/types"; import type { ClientStackParamList } from "../../navigation/types";
// eslint-disable-next-line @typescript-eslint/no-var-requires
const logoGrosSemi = require("../../../assets/logo-gros-semi.png");
const { width: SCREEN_WIDTH } = Dimensions.get("window"); const { width: SCREEN_WIDTH } = Dimensions.get("window");
const CARD_WIDTH = SCREEN_WIDTH - 48; const CARD_WIDTH = SCREEN_WIDTH - 48;