From 79c050d689b68fbb218b16c4be93172faa84cb05 Mon Sep 17 00:00:00 2001 From: Xor290 Date: Tue, 24 Mar 2026 11:51:22 +0100 Subject: [PATCH] chore: add notification telegram --- frontend-admin/app.json | 9 -- frontend-admin/src/api/api_admin.ts | 52 +++++++---- frontend-admin/src/api/api_cabine.ts | 51 +++++++---- frontend-admin/src/api/api_delivery.ts | 33 +++++++ .../src/screens/admin/DashboardScreen.tsx | 65 +++++++++++--- .../src/screens/admin/SettingsScreen.tsx | 49 +++++++++++ .../src/screens/cabine/DashboardScreen.tsx | 67 ++++++++++++-- .../src/screens/delivery/DashboardScreen.tsx | 53 +++++++++++ frontend-admin/src/utils/pushTokenUtils.ts | 38 -------- mobile/app.json | 12 +-- mobile/google-services.json | 29 ------ mobile/src/api/api.ts | 29 ++++-- mobile/src/context/NotificationContext.tsx | 26 ------ mobile/src/screens/client/ProfileScreen.tsx | 88 ++++++++++++++++++- mobile/src/services/pushNotifications.ts | 76 ---------------- 15 files changed, 424 insertions(+), 253 deletions(-) delete mode 100644 frontend-admin/src/utils/pushTokenUtils.ts delete mode 100644 mobile/google-services.json delete mode 100644 mobile/src/services/pushNotifications.ts diff --git a/frontend-admin/app.json b/frontend-admin/app.json index 3dbf50ae..800bf641 100644 --- a/frontend-admin/app.json +++ b/frontend-admin/app.json @@ -36,15 +36,6 @@ "plugins": [ "expo-font", "expo-location", - [ - "expo-notifications", - { - "icon": "./assets/icon.png", - "color": "#ffffff", - "androidMode": "default", - "androidCollapsedTitle": "#{unread_notifications} nouvelles commandes" - } - ], [ "expo-build-properties", { diff --git a/frontend-admin/src/api/api_admin.ts b/frontend-admin/src/api/api_admin.ts index be34d436..076b8767 100644 --- a/frontend-admin/src/api/api_admin.ts +++ b/frontend-admin/src/api/api_admin.ts @@ -760,6 +760,8 @@ export interface AppSettings { nowpayments_api_key: string; nowpayments_ipn_secret: string; nowpayments_currencies: string[]; + telegram_bot_token: string; + telegram_bot_username: string; } export const getSettings = async (): Promise<{ @@ -778,25 +780,6 @@ export const getSettings = async (): Promise<{ } }; -export const registerAdminPushToken = async ( - pushToken: string, -): Promise => { - try { - await apiClient.post(`${V2}/admin/protected/push-token`, { - push_token: pushToken, - }); - } catch { - /* ignore */ - } -}; - -export const unregisterAdminPushToken = async (): Promise => { - try { - await apiClient.delete(`${V2}/admin/protected/push-token`); - } catch { - /* ignore */ - } -}; export interface AppNotification { command_id: number; @@ -818,6 +801,37 @@ export const markAdminNotificationsRead = async (): Promise => { await apiClient.post(`${V2}/admin/protected/notifications/read`); }; +// ============================================ +// TELEGRAM — ADMIN +// ============================================ + +export const getAdminTelegramStatus = async (): Promise<{ linked: boolean; enabled: boolean }> => { + try { + const { data } = await apiClient.get(`${V2}/admin/protected/telegram/status`); + return data; + } catch { + return { linked: false, enabled: false }; + } +}; + +export const generateAdminLinkToken = async (): Promise<{ + link_url?: string; + error?: string; +}> => { + try { + const { data } = await apiClient.post(`${V2}/admin/protected/telegram/link-token`); + return data; + } catch (e: any) { + return { error: e?.response?.data?.error || "Erreur" }; + } +}; + +export const unlinkAdminTelegram = async (): Promise => { + try { + await apiClient.delete(`${V2}/admin/protected/telegram/unlink`); + } catch { /* ignore */ } +}; + export const updateSettings = async ( settings: AppSettings, ): Promise<{ success: boolean; settings?: AppSettings; error?: string }> => { diff --git a/frontend-admin/src/api/api_cabine.ts b/frontend-admin/src/api/api_cabine.ts index 628a5785..25a9981f 100644 --- a/frontend-admin/src/api/api_cabine.ts +++ b/frontend-admin/src/api/api_cabine.ts @@ -354,24 +354,6 @@ export interface PublicSettings { pool_keys: string[]; } -export const registerCabinePushToken = async ( - pushToken: string, -): Promise => { - try { - await apiClient.post(`${API}/push-token`, { push_token: pushToken }); - } catch { - /* ignore */ - } -}; - -export const unregisterCabinePushToken = async (): Promise => { - try { - await apiClient.delete(`${API}/push-token`); - } catch { - /* ignore */ - } -}; - export interface AppNotification { command_id: number; type: string; @@ -454,3 +436,36 @@ export const getAllAddresses = async (): Promise< correct_address: a.correct_address ?? a.CorrectAddress ?? "", })); }; + +// ============================================ +// TELEGRAM — CABINE +// ============================================ + +const CABINE_API = "https://5.181.0.112.nip.io/api/v1/cabine"; + +export const getCabineTelegramStatus = async (): Promise<{ linked: boolean; enabled: boolean }> => { + try { + const { data } = await apiClient.get(`${CABINE_API}/telegram/status`); + return data; + } catch { + return { linked: false, enabled: false }; + } +}; + +export const generateCabineLinkToken = async (): Promise<{ + link_url?: string; + error?: string; +}> => { + try { + const { data } = await apiClient.post(`${CABINE_API}/telegram/link-token`); + return data; + } catch (e: any) { + return { error: e?.response?.data?.error || "Erreur" }; + } +}; + +export const unlinkCabineTelegram = async (): Promise => { + try { + await apiClient.delete(`${CABINE_API}/telegram/unlink`); + } catch { /* ignore */ } +}; diff --git a/frontend-admin/src/api/api_delivery.ts b/frontend-admin/src/api/api_delivery.ts index b9136571..3fa8e2cd 100644 --- a/frontend-admin/src/api/api_delivery.ts +++ b/frontend-admin/src/api/api_delivery.ts @@ -310,3 +310,36 @@ export const markLivreurNotificationsRead = async (): Promise<{ }; } }; + +// ============================================ +// TELEGRAM — LIVREUR +// ============================================ + +export const getLivreurTelegramStatus = async (): Promise<{ linked: boolean; enabled: boolean }> => { + try { + const { data } = await apiClient.get(`${API}/telegram/status`); + return data; + } catch { + return { linked: false, enabled: false }; + } +}; + +export const generateLivreurLinkToken = async (): Promise<{ + link_url?: string; + expires_in?: number; + error?: string; +}> => { + try { + const { data } = await apiClient.post(`${API}/telegram/link-token`); + return data; + } catch (e: any) { + return { error: e?.response?.data?.error || "Erreur" }; + } +}; + +export const unlinkLivreurTelegram = async (): Promise => { + try { + await apiClient.delete(`${API}/telegram/unlink`); + } catch { /* ignore */ } +}; + diff --git a/frontend-admin/src/screens/admin/DashboardScreen.tsx b/frontend-admin/src/screens/admin/DashboardScreen.tsx index 0e769cf9..acf37fb5 100644 --- a/frontend-admin/src/screens/admin/DashboardScreen.tsx +++ b/frontend-admin/src/screens/admin/DashboardScreen.tsx @@ -5,6 +5,9 @@ import { StyleSheet, ScrollView, RefreshControl, + TouchableOpacity, + Linking, + Alert, } from "react-native"; import { Ionicons } from "@expo/vector-icons"; import { spacing, fontSize, borderRadius } from "../../theme"; @@ -16,10 +19,10 @@ import { getAllClients, getAvailableDeliveryPersons, getCommandCountByStatus, - registerAdminPushToken, - unregisterAdminPushToken, + getAdminTelegramStatus, + generateAdminLinkToken, + unlinkAdminTelegram, } from "../../api/api_admin"; -import { getExpoPushToken } from "../../utils/pushTokenUtils"; import LoadingSpinner from "../../components/ui/LoadingSpinner"; interface StatCard { @@ -35,14 +38,9 @@ export default function DashboardScreen() { const [stats, setStats] = useState([]); const [loading, setLoading] = useState(true); const [refreshing, setRefreshing] = useState(false); - - // Enregistrement push token admin au montage - useEffect(() => { - getExpoPushToken().then((token) => { - if (token) registerAdminPushToken(token); - }); - return () => { unregisterAdminPushToken(); }; - }, []); + const [tgLinked, setTgLinked] = useState(false); + const [tgEnabled, setTgEnabled] = useState(false); + const [tgLoading, setTgLoading] = useState(false); const loadStats = useCallback(async () => { try { @@ -106,8 +104,27 @@ export default function DashboardScreen() { useEffect(() => { loadStats(); + getAdminTelegramStatus().then((s) => { setTgLinked(s.linked); setTgEnabled(s.enabled); }); }, [loadStats]); + const handleLinkTelegram = async () => { + setTgLoading(true); + const res = await generateAdminLinkToken(); + setTgLoading(false); + if (res.error || !res.link_url) { + Alert.alert("Erreur", res.error || "Service Telegram non disponible"); + return; + } + Linking.openURL(res.link_url); + }; + + const handleUnlinkTelegram = () => { + Alert.alert("Délier Telegram", "Vous ne recevrez plus de notifications Telegram.", [ + { text: "Annuler", style: "cancel" }, + { text: "Délier", style: "destructive", onPress: async () => { await unlinkAdminTelegram(); setTgLinked(false); } }, + ]); + }; + const onRefresh = async () => { setRefreshing(true); await loadStats(); @@ -202,6 +219,32 @@ export default function DashboardScreen() { ))} + + {tgEnabled && ( + + + + Notifications Telegram + + {tgLinked ? ( + + + + Compte Telegram lié + + + + Délier Telegram + + + ) : ( + + + {tgLoading ? "Génération..." : "Lier Telegram"} + + )} + + )} ); } diff --git a/frontend-admin/src/screens/admin/SettingsScreen.tsx b/frontend-admin/src/screens/admin/SettingsScreen.tsx index 3f8e0791..8dfa41b5 100644 --- a/frontend-admin/src/screens/admin/SettingsScreen.tsx +++ b/frontend-admin/src/screens/admin/SettingsScreen.tsx @@ -659,6 +659,8 @@ export default function SettingsScreen() { nowpayments_api_key: "", nowpayments_ipn_secret: "", nowpayments_currencies: [], + telegram_bot_token: "", + telegram_bot_username: "", }); const [showApiKey, setShowApiKey] = useState(false); const [showIpnSecret, setShowIpnSecret] = useState(false); @@ -1300,6 +1302,53 @@ export default function SettingsScreen() { + {/* ============================================ */} + {/* 🤖 TELEGRAM */} + {/* ============================================ */} + + Notifications Telegram + + + Configurez le bot Telegram pour envoyer des notifications aux utilisateurs qui ont lié leur compte. + + + Token du bot + + Obtenu via @BotFather avec la commande /newbot + + setSettings((p) => ({ ...p, telegram_bot_token: v }))} + placeholder="123456:ABCdefGHI..." + placeholderTextColor={colors.textMuted} + autoCapitalize="none" + secureTextEntry={true} + /> + + + Username du bot + + Sans le @, ex : MonBotNotifications + + setSettings((p) => ({ ...p, telegram_bot_username: v }))} + placeholder="MonBotNotifications" + placeholderTextColor={colors.textMuted} + autoCapitalize="none" + /> + + {settings.telegram_bot_token !== "" && settings.telegram_bot_username !== "" && ( + + + Bot configuré — @{settings.telegram_bot_username} + + )} + + + { - getExpoPushToken().then((token) => { - if (token) registerCabinePushToken(token); - }); - return () => { unregisterCabinePushToken(); }; - }, []); + const [tgLinked, setTgLinked] = useState(false); + const [tgEnabled, setTgEnabled] = useState(false); + const [tgLoading, setTgLoading] = useState(false); const [stats, setStats] = useState< Array<{ label: string; @@ -97,7 +100,27 @@ export default function DashboardScreen() { useEffect(() => { loadStats(); + getCabineTelegramStatus().then((s) => { setTgLinked(s.linked); setTgEnabled(s.enabled); }); }, [loadStats]); + + const handleLinkTelegram = async () => { + setTgLoading(true); + const res = await generateCabineLinkToken(); + setTgLoading(false); + if (res.error || !res.link_url) { + Alert.alert("Erreur", res.error || "Service Telegram non disponible"); + return; + } + Linking.openURL(res.link_url); + }; + + const handleUnlinkTelegram = () => { + Alert.alert("Délier Telegram", "Vous ne recevrez plus de notifications Telegram.", [ + { text: "Annuler", style: "cancel" }, + { text: "Délier", style: "destructive", onPress: async () => { await unlinkCabineTelegram(); setTgLinked(false); } }, + ]); + }; + const onRefresh = async () => { setRefreshing(true); await loadStats(); @@ -191,6 +214,32 @@ export default function DashboardScreen() { ))} + + {tgEnabled && ( + + + + Notifications Telegram + + {tgLinked ? ( + + + + Compte Telegram lié + + + + Délier Telegram + + + ) : ( + + + {tgLoading ? "Génération..." : "Lier Telegram"} + + )} + + )} ); } diff --git a/frontend-admin/src/screens/delivery/DashboardScreen.tsx b/frontend-admin/src/screens/delivery/DashboardScreen.tsx index c967483c..b19a1244 100644 --- a/frontend-admin/src/screens/delivery/DashboardScreen.tsx +++ b/frontend-admin/src/screens/delivery/DashboardScreen.tsx @@ -35,6 +35,9 @@ import { startDelivery, updateDeliveryStatus, updateMyLocation, + getLivreurTelegramStatus, + generateLivreurLinkToken, + unlinkLivreurTelegram, } from "../../api/api_delivery"; import { geocodeAddress, calculateRoute } from "../../api/tomtom"; import type { RouteInfo } from "../../api/tomtom"; @@ -106,6 +109,11 @@ export default function DashboardScreen() { const [detailsDelivery, setDetailsDelivery] = useState(null); + + // Telegram + const [tgLinked, setTgLinked] = useState(false); + const [tgEnabled, setTgEnabled] = useState(false); + const [tgLoading, setTgLoading] = useState(false); const [cancelModal, setCancelModal] = useState<{ visible: boolean; deliveryId: number | null; @@ -279,6 +287,7 @@ export default function DashboardScreen() { useEffect(() => { loadData(); + getLivreurTelegramStatus().then((s) => { setTgLinked(s.linked); setTgEnabled(s.enabled); }); }, [loadData]); useEffect(() => { @@ -741,6 +750,23 @@ export default function DashboardScreen() { // -------------------------------------------------- // Header avec TomTomMap // -------------------------------------------------- + const handleLinkTelegram = async () => { + setTgLoading(true); + const res = await generateLivreurLinkToken(); + setTgLoading(false); + if (res.error || !res.link_url) { + showError("Erreur", res.error || "Service Telegram non disponible"); + return; + } + Linking.openURL(res.link_url); + }; + + const handleUnlinkTelegram = async () => { + await unlinkLivreurTelegram(); + setTgLinked(false); + showSuccess("Telegram délié", "Vous ne recevrez plus de notifications Telegram."); + }; + const renderHeader = () => ( {/* Carte TomTom — toujours montée pour que le ref soit disponible */} @@ -863,6 +889,33 @@ export default function DashboardScreen() { )} + {/* Carte Telegram */} + {tgEnabled && ( + + + + Notifications Telegram + + {tgLinked ? ( + + + + Compte lié + + + + Délier + + + ) : ( + + + {tgLoading ? "Génération..." : "Lier Telegram"} + + )} + + )} + Mes livraisons ({deliveries.length}) diff --git a/frontend-admin/src/utils/pushTokenUtils.ts b/frontend-admin/src/utils/pushTokenUtils.ts deleted file mode 100644 index 959fac1d..00000000 --- a/frontend-admin/src/utils/pushTokenUtils.ts +++ /dev/null @@ -1,38 +0,0 @@ -import * as Notifications from "expo-notifications"; -import * as Device from "expo-device"; -import { Platform } from "react-native"; - -/** - * Demande les permissions et retourne le token Expo push. - * Retourne null si non supporté (simulateur, refus de permission). - */ -export async function getExpoPushToken(): Promise { - if (!Device.isDevice) return null; - - const { status: existing } = await Notifications.getPermissionsAsync(); - let finalStatus = existing; - - if (existing !== "granted") { - const { status } = await Notifications.requestPermissionsAsync(); - finalStatus = status; - } - - if (finalStatus !== "granted") return null; - - if (Platform.OS === "android") { - await Notifications.setNotificationChannelAsync("orders", { - name: "Nouvelles commandes", - importance: Notifications.AndroidImportance.MAX, - vibrationPattern: [0, 250, 250, 250], - sound: "default", - }); - } - - try { - const tokenData = await Notifications.getExpoPushTokenAsync(); - return tokenData.data; - } catch { - // Google Play Services absent (ex: GrapheneOS) — push non disponible - return null; - } -} diff --git a/mobile/app.json b/mobile/app.json index 9f13ace0..32300143 100644 --- a/mobile/app.json +++ b/mobile/app.json @@ -25,8 +25,7 @@ "predictiveBackGestureEnabled": false, "package": "com.uberstup.clientpanel", "versionCode": 1, - "permissions": ["android.permission.VIBRATE"], - "googleServicesFile": "./google-services.json" + "permissions": ["android.permission.VIBRATE"] }, "web": { "favicon": "./assets/icon.png" @@ -34,15 +33,6 @@ "plugins": [ "expo-font", "expo-router", - [ - "expo-notifications", - { - "icon": "./assets/icon.png", - "color": "#ffffff", - "androidMode": "default", - "androidCollapsedTitle": "#{unread_notifications} nouvelles notifications" - } - ], [ "expo-build-properties", { diff --git a/mobile/google-services.json b/mobile/google-services.json deleted file mode 100644 index 2f49d8bd..00000000 --- a/mobile/google-services.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "project_info": { - "project_number": "607244438046", - "project_id": "frontend-client-f3354", - "storage_bucket": "frontend-client-f3354.firebasestorage.app" - }, - "client": [ - { - "client_info": { - "mobilesdk_app_id": "1:607244438046:android:ce55d750fd0f1b98ac3c0f", - "android_client_info": { - "package_name": "com.uberstup.clientpanel" - } - }, - "oauth_client": [], - "api_key": [ - { - "current_key": "AIzaSyA2-og1AoVmwXXY4KTX-J-bt6E5cjiQvmM" - } - ], - "services": { - "appinvite_service": { - "other_platform_oauth_client": [] - } - } - } - ], - "configuration_version": "1" -} \ No newline at end of file diff --git a/mobile/src/api/api.ts b/mobile/src/api/api.ts index 3d491105..997fca2f 100644 --- a/mobile/src/api/api.ts +++ b/mobile/src/api/api.ts @@ -813,17 +813,36 @@ export const getCryptoPaymentStatus = async (commandId: number): Promise => { +// ============================================ +// TELEGRAM +// ============================================ + +export const getTelegramStatus = async (): Promise<{ linked: boolean; enabled: boolean }> => { try { - await apiClient.post(`${V1}/push-token`, { push_token: token }); + const { data } = await apiClient.get(`${V1}/telegram/status`); + return data; } catch { - // silencieux + return { linked: false, enabled: false }; } }; -export const unregisterPushToken = async (): Promise => { +export const generateTelegramLinkToken = async (): Promise<{ + token?: string; + link_url?: string; + expires_in?: number; + error?: string; +}> => { try { - await apiClient.delete(`${V1}/push-token`); + const { data } = await apiClient.post(`${V1}/telegram/link-token`); + return data; + } catch (e: any) { + return { error: e?.response?.data?.error || "Erreur" }; + } +}; + +export const unlinkTelegram = async (): Promise => { + try { + await apiClient.delete(`${V1}/telegram/unlink`); } catch { // silencieux } diff --git a/mobile/src/context/NotificationContext.tsx b/mobile/src/context/NotificationContext.tsx index a3ca494d..a9187ccc 100644 --- a/mobile/src/context/NotificationContext.tsx +++ b/mobile/src/context/NotificationContext.tsx @@ -7,11 +7,9 @@ import React, { useCallback, type ReactNode, } from "react"; -import * as Notifications from "expo-notifications"; import { getClientNotifications, markNotificationsRead } from "../api/api"; import type { ClientNotification } from "../api/api"; import { getToken } from "../auth/tokenStorage"; -import { registerForPushNotifications } from "../services/pushNotifications"; interface ToastData { message: string; @@ -130,30 +128,6 @@ export function NotificationProvider({ children }: { children: ReactNode }) { } }, []); - // Enregistrement push token + listeners (pattern doc Expo) - useEffect(() => { - registerForPushNotifications().catch(console.error); - - const notificationListener = Notifications.addNotificationReceivedListener((notif) => { - const body = notif.request.content.body ?? ""; - const data = notif.request.content.data as any; - showToast(body, getToastType(data?.type ?? "")); - fetchNotifications(); - }); - - const responseListener = Notifications.addNotificationResponseReceivedListener((response) => { - const data = response.notification.request.content.data as any; - if (data?.command_id) { - setNavigateToOrder(data.command_id); - } - }); - - return () => { - notificationListener.remove(); - responseListener.remove(); - }; - }, [fetchNotifications, showToast]); - // Polling toutes les 15 secondes useEffect(() => { fetchNotifications(); diff --git a/mobile/src/screens/client/ProfileScreen.tsx b/mobile/src/screens/client/ProfileScreen.tsx index 2e9ea588..ba30d340 100644 --- a/mobile/src/screens/client/ProfileScreen.tsx +++ b/mobile/src/screens/client/ProfileScreen.tsx @@ -8,11 +8,12 @@ import { Alert, KeyboardAvoidingView, Platform, + Linking, } from "react-native"; import { useFocusEffect } from "@react-navigation/native"; import AsyncStorage from "@react-native-async-storage/async-storage"; import { Ionicons } from "@expo/vector-icons"; -import { getMyProfile, updateMyProfile } from "../../api/api"; +import { getMyProfile, updateMyProfile, getTelegramStatus, generateTelegramLinkToken, unlinkTelegram } from "../../api/api"; import TextInput from "../../components/ui/TextInput"; import Button from "../../components/ui/Button"; import { useTheme } from "../../context/ThemeContext"; @@ -39,14 +40,22 @@ export default function ProfileScreen() { const [loadingProfile, setLoadingProfile] = useState(true); const [savingContact, setSavingContact] = useState(false); + // Telegram + const [telegramLinked, setTelegramLinked] = useState(false); + const [telegramEnabled, setTelegramEnabled] = useState(false); + const [telegramLoading, setTelegramLoading] = useState(false); + const loadData = useCallback(async () => { setLoadingProfile(true); - const [savedAddress, savedPhone, savedSignal, profileRes] = await Promise.all([ + const [savedAddress, savedPhone, savedSignal, profileRes, tgStatus] = await Promise.all([ AsyncStorage.getItem(STORAGE_ADDRESS), AsyncStorage.getItem(STORAGE_PHONE), AsyncStorage.getItem(STORAGE_SIGNAL), getMyProfile(), + getTelegramStatus(), ]); + setTelegramLinked(tgStatus.linked); + setTelegramEnabled(tgStatus.enabled); if (savedAddress !== null) setDefaultAddress(savedAddress); if (savedPhone !== null) setDefaultPhone(savedPhone); @@ -79,6 +88,42 @@ export default function ProfileScreen() { Alert.alert("Enregistré", "Informations par défaut sauvegardées"); }; + const handleLinkTelegram = async () => { + setTelegramLoading(true); + const res = await generateTelegramLinkToken(); + setTelegramLoading(false); + if (res.error || !res.link_url) { + Alert.alert("Erreur", res.error || "Service Telegram non disponible"); + return; + } + Alert.alert( + "Lier Telegram", + "Appuyez sur OK pour ouvrir le bot Telegram et envoyer le message de liaison.", + [ + { text: "Annuler", style: "cancel" }, + { text: "Ouvrir Telegram", onPress: () => Linking.openURL(res.link_url!) }, + ], + ); + }; + + const handleUnlinkTelegram = async () => { + Alert.alert( + "Délier Telegram", + "Vous ne recevrez plus de notifications Telegram. Continuer ?", + [ + { text: "Annuler", style: "cancel" }, + { + text: "Délier", + style: "destructive", + onPress: async () => { + await unlinkTelegram(); + setTelegramLinked(false); + }, + }, + ], + ); + }; + const saveContact = async () => { setSavingContact(true); const res = await updateMyProfile({ nom: nom.trim(), prenom: prenom.trim(), telephone: telephone.trim() }); @@ -280,6 +325,45 @@ export default function ProfileScreen() { + {/* Carte Telegram */} + {telegramEnabled && ( + + + + Notifications Telegram + + + Recevez vos notifications sur Telegram même quand l'application est fermée. + + {telegramLinked ? ( + + + + Compte Telegram lié + + + + Délier Telegram + + + ) : ( + + + + {telegramLoading ? "Génération du lien..." : "Lier mon compte Telegram"} + + + )} + + )} + ); diff --git a/mobile/src/services/pushNotifications.ts b/mobile/src/services/pushNotifications.ts deleted file mode 100644 index fedd36da..00000000 --- a/mobile/src/services/pushNotifications.ts +++ /dev/null @@ -1,76 +0,0 @@ -import * as Notifications from "expo-notifications"; -import * as Device from "expo-device"; -import Constants from "expo-constants"; -import { Platform, Alert } from "react-native"; -import { registerPushToken } from "../api/api"; - -// Comportement des notifs reçues en foreground -Notifications.setNotificationHandler({ - handleNotification: async () => ({ - shouldPlaySound: true, - shouldSetBadge: true, - shouldShowBanner: true, - shouldShowList: true, - }), -}); - -function handleRegistrationError(errorMessage: string) { - console.error("[PUSH]", errorMessage); - Alert.alert("Push Notification Error", errorMessage); -} - -export async function registerForPushNotifications(): Promise< - string | undefined -> { - if (Platform.OS === "android") { - await Notifications.setNotificationChannelAsync("default", { - name: "default", - importance: Notifications.AndroidImportance.MAX, - vibrationPattern: [0, 250, 250, 250], - lightColor: "#FF231F7C", - }); - await Notifications.setNotificationChannelAsync("orders", { - name: "Commandes", - importance: Notifications.AndroidImportance.MAX, - vibrationPattern: [0, 250, 250, 250], - lightColor: "#7c3aed", - }); - } - - if (Device.isDevice) { - const { status: existingStatus } = - await Notifications.getPermissionsAsync(); - let finalStatus = existingStatus; - if (existingStatus !== "granted") { - const { status } = await Notifications.requestPermissionsAsync(); - finalStatus = status; - } - if (finalStatus !== "granted") { - handleRegistrationError( - "Permission not granted to get push token for push notification!", - ); - return; - } - const projectId = - Constants?.expoConfig?.extra?.eas?.projectId ?? - Constants?.easConfig?.projectId; - if (!projectId) { - handleRegistrationError("Project ID not found"); - return; - } - try { - const pushTokenString = ( - await Notifications.getExpoPushTokenAsync({ projectId }) - ).data; - console.log("[PUSH] Token obtenu:", pushTokenString); - await registerPushToken(pushTokenString); - return pushTokenString; - } catch (e: unknown) { - handleRegistrationError(`${e}`); - } - } else { - handleRegistrationError( - "Must use physical device for push notifications", - ); - } -}