chore: add crypto payment
This commit is contained in:
@@ -21,6 +21,19 @@ import { useAlert } from "../../hooks/useAlert";
|
||||
|
||||
const POOL_COLORS = ["#10b981", "#9333ea", "#f97316", "#3b82f6", "#ef4444"];
|
||||
|
||||
const CRYPTO_CURRENCIES = [
|
||||
{ id: "btc", label: "BTC", icon: "₿", color: "#f7931a" },
|
||||
{ id: "eth", label: "ETH", icon: "Ξ", color: "#627eea" },
|
||||
{ id: "ltc", label: "LTC", icon: "Ł", color: "#bebebe" },
|
||||
{ id: "usdt", label: "USDT", icon: "₮", color: "#26a17b" },
|
||||
{ id: "usdttrc20",label: "USDT TRC20",icon: "₮", color: "#c23631" },
|
||||
{ id: "bnb", label: "BNB", icon: "B", color: "#f3ba2f" },
|
||||
{ id: "sol", label: "SOL", icon: "◎", color: "#9945ff" },
|
||||
{ id: "doge", label: "DOGE", icon: "Ð", color: "#c2a633" },
|
||||
{ id: "trx", label: "TRX", icon: "T", color: "#c23631" },
|
||||
{ id: "xmr", label: "XMR", icon: "ɱ", color: "#ff6600" },
|
||||
];
|
||||
|
||||
const DAYS: { key: keyof DeliverySchedule; label: string }[] = [
|
||||
{ key: "monday", label: "Lundi" },
|
||||
{ key: "tuesday", label: "Mardi" },
|
||||
@@ -641,7 +654,13 @@ export default function SettingsScreen() {
|
||||
referral_enabled: true,
|
||||
delivery_schedule: DEFAULT_DELIVERY_SCHEDULE,
|
||||
postal_zones: DEFAULT_POSTAL_ZONES,
|
||||
crypto_payment_enabled: false,
|
||||
nowpayments_api_key: "",
|
||||
nowpayments_ipn_secret: "",
|
||||
nowpayments_currencies: [],
|
||||
});
|
||||
const [showApiKey, setShowApiKey] = useState(false);
|
||||
const [showIpnSecret, setShowIpnSecret] = useState(false);
|
||||
const [categories, setCategories] = useState<Category[]>([]);
|
||||
|
||||
// Refs pour l'auto-sauvegarde au départ de la page
|
||||
@@ -858,6 +877,16 @@ export default function SettingsScreen() {
|
||||
textAlign: "center",
|
||||
},
|
||||
thresholdSep: { fontSize: fontSize.md, color: colors.textMuted },
|
||||
input: {
|
||||
backgroundColor: colors.bgPrimary,
|
||||
borderWidth: 1,
|
||||
borderColor: colors.border,
|
||||
borderRadius: borderRadius.sm,
|
||||
paddingHorizontal: spacing.m,
|
||||
paddingVertical: spacing.s,
|
||||
color: colors.textPrimary,
|
||||
fontSize: fontSize.sm,
|
||||
},
|
||||
saveButton: {
|
||||
backgroundColor: colors.accent,
|
||||
borderRadius: borderRadius.lg,
|
||||
@@ -1124,6 +1153,129 @@ export default function SettingsScreen() {
|
||||
s={s}
|
||||
/>
|
||||
|
||||
{/* Paiement crypto */}
|
||||
<View style={s.section}>
|
||||
<Text style={s.sectionTitle}>Paiement crypto</Text>
|
||||
|
||||
{/* Toggle activation */}
|
||||
<View style={[s.row, s.rowFirst]}>
|
||||
<View style={s.rowLeft}>
|
||||
<Text style={s.rowLabel}>Paiement crypto activé</Text>
|
||||
<Text style={s.rowDesc}>
|
||||
Les clients peuvent payer leurs commandes en cryptomonnaie via NowPayments.
|
||||
</Text>
|
||||
</View>
|
||||
<Switch
|
||||
value={settings.crypto_payment_enabled}
|
||||
onValueChange={(v) =>
|
||||
setSettings((prev) => ({ ...prev, crypto_payment_enabled: v }))
|
||||
}
|
||||
trackColor={{ false: colors.border, true: colors.accent }}
|
||||
thumbColor="#fff"
|
||||
/>
|
||||
</View>
|
||||
|
||||
{/* Config NowPayments */}
|
||||
<View
|
||||
pointerEvents={settings.crypto_payment_enabled ? "auto" : "none"}
|
||||
style={{ opacity: settings.crypto_payment_enabled ? 1 : 0.4, paddingHorizontal: spacing.l, paddingBottom: spacing.m, borderTopWidth: 1, borderTopColor: colors.border, paddingTop: spacing.m, gap: spacing.m }}
|
||||
>
|
||||
{/* Clé API */}
|
||||
<View>
|
||||
<Text style={[s.rowLabel, { marginBottom: spacing.xs }]}>Clé API NowPayments</Text>
|
||||
<View style={{ flexDirection: "row", alignItems: "center", gap: spacing.s }}>
|
||||
<TextInput
|
||||
style={[s.input, { flex: 1, fontFamily: "monospace" }]}
|
||||
value={settings.nowpayments_api_key}
|
||||
onChangeText={(v) => setSettings((p) => ({ ...p, nowpayments_api_key: v }))}
|
||||
placeholder="Votre clé API NowPayments"
|
||||
placeholderTextColor={colors.textSecondary}
|
||||
secureTextEntry={!showApiKey}
|
||||
autoCapitalize="none"
|
||||
autoCorrect={false}
|
||||
/>
|
||||
<TouchableOpacity onPress={() => setShowApiKey((x) => !x)} style={{ padding: spacing.xs }}>
|
||||
<Ionicons name={showApiKey ? "eye-off-outline" : "eye-outline"} size={20} color={colors.textSecondary} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Secret IPN */}
|
||||
<View>
|
||||
<Text style={[s.rowLabel, { marginBottom: spacing.xs }]}>Secret IPN</Text>
|
||||
<View style={{ flexDirection: "row", alignItems: "center", gap: spacing.s }}>
|
||||
<TextInput
|
||||
style={[s.input, { flex: 1, fontFamily: "monospace" }]}
|
||||
value={settings.nowpayments_ipn_secret}
|
||||
onChangeText={(v) => setSettings((p) => ({ ...p, nowpayments_ipn_secret: v }))}
|
||||
placeholder="Secret IPN pour la vérification des webhooks"
|
||||
placeholderTextColor={colors.textSecondary}
|
||||
secureTextEntry={!showIpnSecret}
|
||||
autoCapitalize="none"
|
||||
autoCorrect={false}
|
||||
/>
|
||||
<TouchableOpacity onPress={() => setShowIpnSecret((x) => !x)} style={{ padding: spacing.xs }}>
|
||||
<Ionicons name={showIpnSecret ? "eye-off-outline" : "eye-outline"} size={20} color={colors.textSecondary} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<Text style={[s.rowDesc, { marginTop: spacing.xs }]}>
|
||||
URL IPN à configurer sur NowPayments :{"\n"}
|
||||
<Text style={{ color: colors.accent, fontSize: fontSize.xs }}>
|
||||
https://5.181.0.112.nip.io/api/v1/webhooks/nowpayments
|
||||
</Text>
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
{/* Cryptos acceptées */}
|
||||
<View>
|
||||
<Text style={[s.rowLabel, { marginBottom: spacing.xs }]}>Cryptomonnaies acceptées</Text>
|
||||
<Text style={[s.rowDesc, { marginBottom: spacing.s }]}>
|
||||
Sélectionnez les cryptos que vos clients peuvent utiliser pour payer.
|
||||
</Text>
|
||||
<View style={{ flexDirection: "row", flexWrap: "wrap", gap: spacing.s }}>
|
||||
{CRYPTO_CURRENCIES.map((coin) => {
|
||||
const selected = (settings.nowpayments_currencies ?? []).includes(coin.id);
|
||||
return (
|
||||
<TouchableOpacity
|
||||
key={coin.id}
|
||||
onPress={() => {
|
||||
setSettings((prev) => {
|
||||
const current = prev.nowpayments_currencies ?? [];
|
||||
const updated = selected
|
||||
? current.filter((c) => c !== coin.id)
|
||||
: [...current, coin.id];
|
||||
return { ...prev, nowpayments_currencies: updated };
|
||||
});
|
||||
}}
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
gap: spacing.xs,
|
||||
paddingHorizontal: spacing.m,
|
||||
paddingVertical: spacing.s,
|
||||
borderRadius: borderRadius.full,
|
||||
borderWidth: 1.5,
|
||||
borderColor: selected ? coin.color : colors.border,
|
||||
backgroundColor: selected ? coin.color + "22" : colors.bgSecondary,
|
||||
}}
|
||||
>
|
||||
<Text style={{ fontSize: 16 }}>{coin.icon}</Text>
|
||||
<Text style={{ fontSize: fontSize.sm, fontWeight: "600", color: selected ? coin.color : colors.textSecondary }}>
|
||||
{coin.label}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
})}
|
||||
</View>
|
||||
{(settings.nowpayments_currencies ?? []).length === 0 && (
|
||||
<Text style={[s.rowDesc, { color: "#ef4444", marginTop: spacing.s }]}>
|
||||
⚠ Sélectionnez au moins une cryptomonnaie.
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<TouchableOpacity
|
||||
style={s.saveButton}
|
||||
onPress={handleSave}
|
||||
|
||||
Reference in New Issue
Block a user