This commit is contained in:
@@ -446,11 +446,10 @@ export const createProductAdmin = async (formData: FormData) => {
|
||||
`${V2}/admin/protected/products`,
|
||||
formData,
|
||||
{
|
||||
headers: { "Content-Type": "multipart/form-data" },
|
||||
timeout: 120000,
|
||||
},
|
||||
);
|
||||
return { success: true, data: data.data, message: data.message };
|
||||
return { success: true, data: data.product, message: data.message };
|
||||
};
|
||||
|
||||
export const updateProductAdmin = async (
|
||||
@@ -749,7 +748,7 @@ export const uploadProductMediaAdmin = async (
|
||||
const { data } = await apiClient.post(
|
||||
`${V2}/admin/protected/products/${productId}/media`,
|
||||
fd,
|
||||
{ headers: { "Content-Type": "multipart/form-data" }, timeout: 120000 },
|
||||
{ timeout: 120000 },
|
||||
);
|
||||
return { success: true, media: data.media, message: data.message };
|
||||
};
|
||||
|
||||
@@ -62,12 +62,12 @@ interface PendingMedia {
|
||||
// Les catégories sont chargées dynamiquement depuis l'API
|
||||
|
||||
const UNITS = [
|
||||
{ value: "u", label: "u" },
|
||||
{ value: "kg", label: "kg" },
|
||||
{ value: "g", label: "g" },
|
||||
{ value: "u", label: "u" },
|
||||
{ value: "kg", label: "kg" },
|
||||
{ value: "g", label: "g" },
|
||||
{ value: "bag", label: "bag" },
|
||||
{ value: "l", label: "l" },
|
||||
{ value: "cl", label: "cl" },
|
||||
{ value: "l", label: "l" },
|
||||
{ value: "cl", label: "cl" },
|
||||
{ value: "pcs", label: "pcs" },
|
||||
];
|
||||
|
||||
@@ -247,11 +247,7 @@ export default function ProductsScreen() {
|
||||
}
|
||||
|
||||
const result = await ImagePicker.launchImageLibraryAsync({
|
||||
mediaTypes:
|
||||
type === "image"
|
||||
? ImagePicker.MediaTypeOptions.Images
|
||||
: ImagePicker.MediaTypeOptions.Videos,
|
||||
quality: 0.8,
|
||||
mediaTypes: type === "image" ? ["images"] : ["videos"],
|
||||
allowsMultipleSelection: true,
|
||||
});
|
||||
|
||||
@@ -358,7 +354,10 @@ export default function ProductsScreen() {
|
||||
prices.forEach((p, i) => {
|
||||
fd.append(`prices[${i}][quantity]`, String(p.quantity));
|
||||
fd.append(`prices[${i}][price]`, String(p.price));
|
||||
fd.append(`prices[${i}][active_price]`, p.active_price ? "true" : "false");
|
||||
fd.append(
|
||||
`prices[${i}][active_price]`,
|
||||
p.active_price ? "true" : "false",
|
||||
);
|
||||
});
|
||||
|
||||
// Attacher les médias en attente
|
||||
@@ -388,13 +387,18 @@ export default function ProductsScreen() {
|
||||
m.mediaType,
|
||||
);
|
||||
} catch (uploadErr: any) {
|
||||
const msg = uploadErr?.response?.data?.error || uploadErr?.message || `Erreur upload ${m.mediaType}`;
|
||||
const msg =
|
||||
uploadErr?.response?.data?.error ||
|
||||
uploadErr?.message ||
|
||||
`Erreur upload ${m.mediaType}`;
|
||||
uploadErrors.push(msg);
|
||||
}
|
||||
}
|
||||
setUploadingMedia(false);
|
||||
if (uploadErrors.length > 0) {
|
||||
setFormError(`Erreur upload média: ${uploadErrors.join(", ")}`);
|
||||
setFormError(
|
||||
`Erreur upload média: ${uploadErrors.join(", ")}`,
|
||||
);
|
||||
await loadData();
|
||||
return;
|
||||
}
|
||||
@@ -645,8 +649,14 @@ export default function ProductsScreen() {
|
||||
borderColor: "#22c55e",
|
||||
backgroundColor: "#22c55e20",
|
||||
},
|
||||
comingSoonBtnText: { color: colors.textMuted, fontSize: fontSize.sm },
|
||||
comingSoonBtnTextActive: { color: "#22c55e", fontWeight: "700" },
|
||||
comingSoonBtnText: {
|
||||
color: colors.textMuted,
|
||||
fontSize: fontSize.sm,
|
||||
},
|
||||
comingSoonBtnTextActive: {
|
||||
color: "#22c55e",
|
||||
fontWeight: "700",
|
||||
},
|
||||
|
||||
// Prices
|
||||
sectionHeader: {
|
||||
@@ -808,7 +818,10 @@ export default function ProductsScreen() {
|
||||
<Text style={styles.name}>{item.name}</Text>
|
||||
<Badge
|
||||
label={item.category}
|
||||
color={categories.find(c => c.name === item.category)?.color || colors.accent}
|
||||
color={
|
||||
categories.find((c) => c.name === item.category)
|
||||
?.color || colors.accent
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
@@ -843,9 +856,18 @@ export default function ProductsScreen() {
|
||||
)}
|
||||
</View>
|
||||
)}
|
||||
<Text style={styles.info}>Stock: {item.stock} {item.unit || "u"}</Text>
|
||||
<Text style={styles.info}>
|
||||
Stock: {item.stock} {item.unit || "u"}
|
||||
</Text>
|
||||
{item.prices && item.prices.length > 0 && (
|
||||
<View style={{ flexDirection: "row", flexWrap: "wrap", gap: 4, marginTop: 2 }}>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
flexWrap: "wrap",
|
||||
gap: 4,
|
||||
marginTop: 2,
|
||||
}}
|
||||
>
|
||||
{item.prices.map((p, i) => (
|
||||
<Text
|
||||
key={i}
|
||||
@@ -858,7 +880,8 @@ export default function ProductsScreen() {
|
||||
},
|
||||
]}
|
||||
>
|
||||
{p.quantity}{item.unit || "u"} = {p.price}€
|
||||
{p.quantity}
|
||||
{item.unit || "u"} = {p.price}€
|
||||
{i < item.prices!.length - 1 ? " |" : ""}
|
||||
</Text>
|
||||
))}
|
||||
@@ -1024,7 +1047,8 @@ export default function ProductsScreen() {
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.comingSoonBtn,
|
||||
form.comingSoon && styles.comingSoonBtnActive,
|
||||
form.comingSoon &&
|
||||
styles.comingSoonBtnActive,
|
||||
]}
|
||||
onPress={() =>
|
||||
setForm((f) => {
|
||||
@@ -1032,16 +1056,24 @@ export default function ProductsScreen() {
|
||||
return {
|
||||
...f,
|
||||
comingSoon: next,
|
||||
prices: f.prices.map((p) => ({ ...p, active: !next })),
|
||||
prices: f.prices.map((p) => ({
|
||||
...p,
|
||||
active: !next,
|
||||
})),
|
||||
};
|
||||
})
|
||||
}
|
||||
>
|
||||
<Text style={[
|
||||
styles.comingSoonBtnText,
|
||||
form.comingSoon && styles.comingSoonBtnTextActive,
|
||||
]}>
|
||||
{form.comingSoon ? "À venir (activé)" : "Marquer comme «À venir»"}
|
||||
<Text
|
||||
style={[
|
||||
styles.comingSoonBtnText,
|
||||
form.comingSoon &&
|
||||
styles.comingSoonBtnTextActive,
|
||||
]}
|
||||
>
|
||||
{form.comingSoon
|
||||
? "À venir (activé)"
|
||||
: "Marquer comme «À venir»"}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
@@ -1140,9 +1172,18 @@ export default function ProductsScreen() {
|
||||
onPress={() => togglePriceActive(idx)}
|
||||
>
|
||||
<Ionicons
|
||||
name={p.active ? "checkmark-circle" : "close-circle"}
|
||||
name={
|
||||
p.active
|
||||
? "checkmark-circle"
|
||||
: "close-circle"
|
||||
}
|
||||
size={22}
|
||||
color={p.active ? colors.success || "#22c55e" : colors.danger}
|
||||
color={
|
||||
p.active
|
||||
? colors.success ||
|
||||
"#22c55e"
|
||||
: colors.danger
|
||||
}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
{form.prices.length > 1 && (
|
||||
|
||||
Reference in New Issue
Block a user