@wasto/cms-components 1.5.11 → 1.5.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -133,13 +133,13 @@ function useTheme() {
133
133
  }
134
134
 
135
135
  // src/hooks/useBlogPosts.ts
136
- import { useCallback as useCallback7, useEffect as useEffect8, useState as useState7 } from "react";
136
+ import { useCallback as useCallback7, useEffect as useEffect9, useState as useState7 } from "react";
137
137
 
138
138
  // src/contexts/WastoContext.tsx
139
139
  import {
140
140
  createContext as createContext6,
141
141
  useContext as useContext7,
142
- useEffect as useEffect6,
142
+ useEffect as useEffect7,
143
143
  useMemo as useMemo7
144
144
  } from "react";
145
145
 
@@ -212,18 +212,22 @@ function LocalProvider({
212
212
  };
213
213
  let resolvedDeviceId = null;
214
214
  if (!previewMode) {
215
- const newDeviceId = generateDeviceId();
215
+ const existingDeviceId = await AsyncStorage.getItem(keys.device);
216
+ const nextDeviceId = existingDeviceId || generateDeviceId();
216
217
  await client.public.analytics.track({
217
- id: newDeviceId,
218
+ id: nextDeviceId,
218
219
  cityId,
220
+ wasteCollectionPlaceId: placeId,
219
221
  platform: Platform.OS,
220
222
  osVersion: null,
221
223
  appVersion: null,
222
224
  deviceModel: null
223
225
  });
224
- await AsyncStorage.setItem(keys.device, newDeviceId);
225
- setDeviceId(newDeviceId);
226
- resolvedDeviceId = newDeviceId;
226
+ if (!existingDeviceId) {
227
+ await AsyncStorage.setItem(keys.device, nextDeviceId);
228
+ }
229
+ setDeviceId(nextDeviceId);
230
+ resolvedDeviceId = nextDeviceId;
227
231
  } else {
228
232
  setDeviceId(null);
229
233
  }
@@ -297,6 +301,25 @@ function LocalProvider({
297
301
  };
298
302
  void loadLocalData();
299
303
  }, [keys, previewMode]);
304
+ useEffect(() => {
305
+ if (previewMode || !deviceId || !selectedCityId) return;
306
+ void client.public.analytics.track({
307
+ id: deviceId,
308
+ cityId: selectedCityId,
309
+ wasteCollectionPlaceId: selectedPlaceId,
310
+ platform: Platform.OS,
311
+ osVersion: null,
312
+ appVersion: null,
313
+ deviceModel: null
314
+ }).catch(() => {
315
+ });
316
+ }, [
317
+ client.public.analytics,
318
+ deviceId,
319
+ previewMode,
320
+ selectedCityId,
321
+ selectedPlaceId
322
+ ]);
300
323
  return /* @__PURE__ */ jsx2(
301
324
  LocalContext,
302
325
  {
@@ -705,13 +728,16 @@ function getCollectionsForDay(wasteTypes, wasteCollectionPlaces, dateOffset, sel
705
728
  return targetDate.getTime() >= from.getTime() && targetDate.getTime() < to.getTime();
706
729
  });
707
730
  if (hasException) continue;
708
- if (day.biweekly && day.startDate) {
731
+ if (day.startDate) {
709
732
  const start = new Date(day.startDate);
733
+ start.setHours(0, 0, 0, 0);
734
+ const everyWeeks = Math.max(1, Number(day.everyWeeks) || 1);
710
735
  const diffDays = Math.floor(
711
736
  (targetDate.getTime() - start.getTime()) / (1e3 * 60 * 60 * 24)
712
737
  );
713
738
  const weeks = Math.floor(diffDays / 7);
714
- if (weeks < 0 || weeks % 2 !== 0) continue;
739
+ if (weeks < 0) continue;
740
+ if (everyWeeks > 1 && weeks % everyWeeks !== 0) continue;
715
741
  }
716
742
  const wt = wasteTypes.find((w) => w.id === day.wasteTypeId);
717
743
  if (!wt) continue;
@@ -2106,6 +2132,155 @@ var styles4 = StyleSheet4.create({
2106
2132
  }
2107
2133
  });
2108
2134
 
2135
+ // src/components/push/PushTokenRegistrar.tsx
2136
+ import { useEffect as useEffect6, useRef as useRef3 } from "react";
2137
+ import { AppState, Platform as Platform5 } from "react-native";
2138
+
2139
+ // src/push/registerExpoPushToken.ts
2140
+ import { Platform as Platform4 } from "react-native";
2141
+ var notificationsModule;
2142
+ var constantsModule;
2143
+ var handlerConfigured = false;
2144
+ function loadNotifications() {
2145
+ if (notificationsModule !== void 0) return notificationsModule;
2146
+ try {
2147
+ notificationsModule = __require("expo-notifications");
2148
+ } catch {
2149
+ notificationsModule = null;
2150
+ }
2151
+ return notificationsModule;
2152
+ }
2153
+ function loadConstants() {
2154
+ if (constantsModule !== void 0) return constantsModule;
2155
+ try {
2156
+ const mod = __require("expo-constants");
2157
+ constantsModule = "default" in mod && mod.default ? mod.default : mod;
2158
+ } catch {
2159
+ constantsModule = null;
2160
+ }
2161
+ return constantsModule;
2162
+ }
2163
+ function resolveEasProjectId() {
2164
+ const Constants = loadConstants();
2165
+ const fromExtra = Constants?.expoConfig?.extra?.eas?.projectId;
2166
+ const fromEasConfig = Constants?.easConfig?.projectId;
2167
+ const fromEnv = typeof process !== "undefined" ? String(process.env.EXPO_PUBLIC_EAS_PROJECT_ID ?? "").trim() : "";
2168
+ const projectId = String(fromExtra || fromEasConfig || fromEnv || "").trim();
2169
+ return projectId || null;
2170
+ }
2171
+ async function registerExpoPushToken(options) {
2172
+ if (Platform4.OS === "web") return null;
2173
+ const deviceId = options.deviceId?.trim();
2174
+ if (!deviceId) return null;
2175
+ const Notifications = loadNotifications();
2176
+ if (!Notifications) {
2177
+ if (__DEV__) {
2178
+ console.warn(
2179
+ "[wasto] expo-notifications is not installed; push registration skipped"
2180
+ );
2181
+ }
2182
+ return null;
2183
+ }
2184
+ const projectId = resolveEasProjectId();
2185
+ if (!projectId) {
2186
+ if (__DEV__) {
2187
+ console.warn(
2188
+ "[wasto] EAS projectId missing (extra.eas.projectId or EXPO_PUBLIC_EAS_PROJECT_ID); push registration skipped"
2189
+ );
2190
+ }
2191
+ return null;
2192
+ }
2193
+ if (!handlerConfigured) {
2194
+ Notifications.setNotificationHandler({
2195
+ handleNotification: async () => ({
2196
+ shouldShowAlert: true,
2197
+ shouldPlaySound: true,
2198
+ shouldSetBadge: false,
2199
+ shouldShowBanner: true,
2200
+ shouldShowList: true
2201
+ })
2202
+ });
2203
+ handlerConfigured = true;
2204
+ }
2205
+ if (Platform4.OS === "android") {
2206
+ await Notifications.setNotificationChannelAsync("default", {
2207
+ name: "default",
2208
+ importance: Notifications.AndroidImportance.MAX,
2209
+ vibrationPattern: [0, 250, 250, 250],
2210
+ lightColor: "#FF231F7C"
2211
+ });
2212
+ }
2213
+ const { status: existingStatus } = await Notifications.getPermissionsAsync();
2214
+ let finalStatus = existingStatus;
2215
+ if (existingStatus !== "granted") {
2216
+ const { status } = await Notifications.requestPermissionsAsync();
2217
+ finalStatus = status;
2218
+ }
2219
+ if (finalStatus !== "granted") return null;
2220
+ const push = await Notifications.getExpoPushTokenAsync({ projectId });
2221
+ const token = push?.data?.trim();
2222
+ if (!token) return null;
2223
+ await options.registerPushToken(deviceId, token);
2224
+ return token;
2225
+ }
2226
+
2227
+ // src/components/push/PushTokenRegistrar.tsx
2228
+ function PushTokenRegistrar() {
2229
+ const { deviceId, selectedCityId, selectedPlaceId } = useLocal();
2230
+ const { previewMode, reportError: reportError2 } = useWasto();
2231
+ const client = useWastoClient();
2232
+ const lastRegistered = useRef3(null);
2233
+ const inFlight = useRef3(false);
2234
+ useEffect6(() => {
2235
+ if (previewMode || Platform5.OS === "web" || !deviceId) return;
2236
+ let cancelled = false;
2237
+ const tryRegister = async () => {
2238
+ if (cancelled || inFlight.current) return;
2239
+ const registrationKey = `${deviceId}:${selectedPlaceId ?? ""}:${selectedCityId ?? ""}`;
2240
+ if (lastRegistered.current === registrationKey) return;
2241
+ inFlight.current = true;
2242
+ try {
2243
+ const token = await registerExpoPushToken({
2244
+ deviceId,
2245
+ registerPushToken: (id, pushToken) => client.public.devices.registerPushToken(id, {
2246
+ token: pushToken,
2247
+ cityId: selectedCityId,
2248
+ wasteCollectionPlaceId: selectedPlaceId
2249
+ })
2250
+ });
2251
+ if (!cancelled && token) {
2252
+ lastRegistered.current = registrationKey;
2253
+ }
2254
+ } catch (error) {
2255
+ if (!cancelled) {
2256
+ reportError2(error, { source: "push", deviceId });
2257
+ }
2258
+ } finally {
2259
+ inFlight.current = false;
2260
+ }
2261
+ };
2262
+ void tryRegister();
2263
+ const sub = AppState.addEventListener("change", (state) => {
2264
+ if (state === "active") {
2265
+ lastRegistered.current = null;
2266
+ void tryRegister();
2267
+ }
2268
+ });
2269
+ return () => {
2270
+ cancelled = true;
2271
+ sub.remove();
2272
+ };
2273
+ }, [
2274
+ client.public.devices,
2275
+ deviceId,
2276
+ previewMode,
2277
+ reportError2,
2278
+ selectedCityId,
2279
+ selectedPlaceId
2280
+ ]);
2281
+ return null;
2282
+ }
2283
+
2109
2284
  // src/components/safe-area/OptionalSafeAreaProvider.tsx
2110
2285
  import { useContext as useContext6 } from "react";
2111
2286
  import {
@@ -2217,7 +2392,7 @@ function WastoProvider(props) {
2217
2392
  );
2218
2393
  const previewMode = Boolean(props.previewMode);
2219
2394
  const sentryConfig = props.sentry;
2220
- useEffect6(() => {
2395
+ useEffect7(() => {
2221
2396
  if (!sentryConfig) return;
2222
2397
  initWastoSentry({
2223
2398
  ...sentryConfig,
@@ -2252,11 +2427,14 @@ function WastoProvider(props) {
2252
2427
  }),
2253
2428
  [apiUrl, appId, cityGroupId, previewMode, reportError2, onRequestError]
2254
2429
  );
2255
- return /* @__PURE__ */ jsx10(WastoContext, { value, children: /* @__PURE__ */ jsx10(OptionalSafeAreaProvider, { children: /* @__PURE__ */ jsx10(LocalProvider, { previewMode, children: /* @__PURE__ */ jsx10(ChallengesProvider, { children: /* @__PURE__ */ jsx10(AnnouncementsProvider, { apiUrl, children: /* @__PURE__ */ jsx10(ThemeProvider, { theme: props.theme, children: /* @__PURE__ */ jsxs5(AppDataProvider, { apiUrl, children: [
2256
- props.children,
2257
- /* @__PURE__ */ jsx10(SelectStreetModal, {}),
2258
- /* @__PURE__ */ jsx10(AnnouncementModal, {})
2259
- ] }) }) }) }) }) }) });
2430
+ return /* @__PURE__ */ jsx10(WastoContext, { value, children: /* @__PURE__ */ jsx10(OptionalSafeAreaProvider, { children: /* @__PURE__ */ jsxs5(LocalProvider, { previewMode, children: [
2431
+ /* @__PURE__ */ jsx10(PushTokenRegistrar, {}),
2432
+ /* @__PURE__ */ jsx10(ChallengesProvider, { children: /* @__PURE__ */ jsx10(AnnouncementsProvider, { apiUrl, children: /* @__PURE__ */ jsx10(ThemeProvider, { theme: props.theme, children: /* @__PURE__ */ jsxs5(AppDataProvider, { apiUrl, children: [
2433
+ props.children,
2434
+ /* @__PURE__ */ jsx10(SelectStreetModal, {}),
2435
+ /* @__PURE__ */ jsx10(AnnouncementModal, {})
2436
+ ] }) }) }) })
2437
+ ] }) }) });
2260
2438
  }
2261
2439
  function useWasto() {
2262
2440
  const context = useContext7(WastoContext);
@@ -2416,7 +2594,7 @@ function formatArticleDate(value) {
2416
2594
  }
2417
2595
 
2418
2596
  // src/hooks/useNextCollection.ts
2419
- import { useCallback as useCallback6, useEffect as useEffect7, useMemo as useMemo8, useState as useState6 } from "react";
2597
+ import { useCallback as useCallback6, useEffect as useEffect8, useMemo as useMemo8, useState as useState6 } from "react";
2420
2598
  function useNextCollection(options = {}) {
2421
2599
  const { selectedCityId, selectedPlaceId: localPlaceId } = useLocal();
2422
2600
  const appData = useOptionalAppData();
@@ -2466,7 +2644,7 @@ function useNextCollection(options = {}) {
2466
2644
  setIsLoading(false);
2467
2645
  }
2468
2646
  }, [appData, client.public.cities, pageSize, resolvedCityId, useShared]);
2469
- useEffect7(() => {
2647
+ useEffect8(() => {
2470
2648
  void fetchData();
2471
2649
  }, [fetchData]);
2472
2650
  const sharedWasteTypes = useShared && appData ? appData.wasteTypes : wasteTypes;
@@ -2524,7 +2702,7 @@ function useBlogPosts(options = {}) {
2524
2702
  setIsLoading(false);
2525
2703
  }
2526
2704
  }, [cityGroupId, client.public.blogPosts, pageSize]);
2527
- useEffect8(() => {
2705
+ useEffect9(() => {
2528
2706
  void fetchPosts();
2529
2707
  }, [fetchPosts]);
2530
2708
  return { posts, isLoading, error, refetch: fetchPosts };
@@ -2534,7 +2712,7 @@ function useBlogPost(articleId) {
2534
2712
  const [post, setPost] = useState7(null);
2535
2713
  const [isLoading, setIsLoading] = useState7(false);
2536
2714
  const [error, setError] = useState7(null);
2537
- useEffect8(() => {
2715
+ useEffect9(() => {
2538
2716
  const id = articleId.trim();
2539
2717
  if (!id) {
2540
2718
  setPost(null);
@@ -3209,7 +3387,7 @@ function useChallenges(_options = {}) {
3209
3387
  }
3210
3388
 
3211
3389
  // src/hooks/useBadges.ts
3212
- import { useCallback as useCallback8, useEffect as useEffect9, useState as useState11 } from "react";
3390
+ import { useCallback as useCallback8, useEffect as useEffect10, useState as useState11 } from "react";
3213
3391
  function useBadges(options = {}) {
3214
3392
  const { selectedCityId } = useLocal();
3215
3393
  const resolvedCityId = options.cityId ?? selectedCityId ?? null;
@@ -3245,7 +3423,7 @@ function useBadges(options = {}) {
3245
3423
  setIsLoading(false);
3246
3424
  }
3247
3425
  }, [client.public.cities, page, pageSize, resolvedCityId]);
3248
- useEffect9(() => {
3426
+ useEffect10(() => {
3249
3427
  void fetchBadges();
3250
3428
  }, [fetchBadges]);
3251
3429
  const getBadgeById = useCallback8((id) => badges.find((b) => b.id === id), [badges]);
@@ -3485,7 +3663,7 @@ var styles13 = StyleSheet14.create({
3485
3663
  // src/components/challenge/ChallengesModal.tsx
3486
3664
  import { Dimensions as Dimensions4, Modal as Modal6, Pressable as Pressable7, ScrollView as ScrollView7, StyleSheet as StyleSheet18, Text as Text15, View as View17 } from "react-native";
3487
3665
  import { Play as Play2, Trophy as Trophy2, XIcon as XIcon4 } from "lucide-react-native";
3488
- import { useEffect as useEffect11, useState as useState15 } from "react";
3666
+ import { useEffect as useEffect12, useState as useState15 } from "react";
3489
3667
 
3490
3668
  // src/components/challenge/ChallengeModal.tsx
3491
3669
  import { Dimensions as Dimensions3, Pressable as Pressable6, ScrollView as ScrollView6, StyleSheet as StyleSheet17, Text as Text14, View as View16 } from "react-native";
@@ -3493,7 +3671,7 @@ import { Play, Trophy, XIcon as XIcon3 } from "lucide-react-native";
3493
3671
  import { useState as useState14 } from "react";
3494
3672
 
3495
3673
  // src/components/challenge/QuizModal.tsx
3496
- import { useEffect as useEffect10, useMemo as useMemo13, useRef as useRef3, useState as useState13 } from "react";
3674
+ import { useEffect as useEffect11, useMemo as useMemo13, useRef as useRef4, useState as useState13 } from "react";
3497
3675
  import {
3498
3676
  ActivityIndicator as ActivityIndicator7,
3499
3677
  Dimensions as Dimensions2,
@@ -3793,9 +3971,9 @@ function QuizModal({
3793
3971
  const [correct, setCorrect] = useState13(0);
3794
3972
  const [incorrect, setIncorrect] = useState13(0);
3795
3973
  const [showResults, setShowResults] = useState13(false);
3796
- const completedRef = useRef3(false);
3974
+ const completedRef = useRef4(false);
3797
3975
  const question = questions[index];
3798
- useEffect10(() => {
3976
+ useEffect11(() => {
3799
3977
  setIndex(0);
3800
3978
  setSelected(null);
3801
3979
  setCorrect(0);
@@ -4285,7 +4463,7 @@ function ChallengesModal({
4285
4463
  const bottomInset = useSafeAreaPadding(["bottom"]);
4286
4464
  const [selectedChallengeId, setSelectedChallengeId] = useState15(null);
4287
4465
  const selectedChallenge = selectedChallengeId != null ? challenges.find((c) => c.id === selectedChallengeId) ?? null : null;
4288
- useEffect11(() => {
4466
+ useEffect12(() => {
4289
4467
  if (!visible) setSelectedChallengeId(null);
4290
4468
  }, [visible]);
4291
4469
  const handleSelectChallenge = (challenge) => () => {
@@ -5016,7 +5194,7 @@ var styles19 = StyleSheet20.create({
5016
5194
  });
5017
5195
 
5018
5196
  // src/components/chat/Chat.tsx
5019
- import { useCallback as useCallback9, useEffect as useEffect12, useRef as useRef4, useState as useState18 } from "react";
5197
+ import { useCallback as useCallback9, useEffect as useEffect13, useRef as useRef5, useState as useState18 } from "react";
5020
5198
  import {
5021
5199
  ActivityIndicator as ActivityIndicator10,
5022
5200
  FlatList as FlatList2,
@@ -5391,11 +5569,11 @@ function Chat({ title, cityId, cityGroupId: cityGroupIdProp }) {
5391
5569
  null
5392
5570
  );
5393
5571
  const [pendingSectors, setPendingSectors] = useState18([]);
5394
- const listRef = useRef4(null);
5395
- useEffect12(() => {
5572
+ const listRef = useRef5(null);
5573
+ useEffect13(() => {
5396
5574
  setNeedsAddress(!hasAddress);
5397
5575
  }, [hasAddress]);
5398
- useEffect12(() => {
5576
+ useEffect13(() => {
5399
5577
  let cancelled = false;
5400
5578
  (async () => {
5401
5579
  if (!cityGroupId && !resolvedCityId) {
@@ -5423,7 +5601,7 @@ function Chat({ title, cityId, cityGroupId: cityGroupIdProp }) {
5423
5601
  cancelled = true;
5424
5602
  };
5425
5603
  }, [client, cityGroupId, resolvedCityId]);
5426
- useEffect12(() => {
5604
+ useEffect13(() => {
5427
5605
  if (!needsAddress || !open) return;
5428
5606
  const trimmed = addressQuery.trim();
5429
5607
  if (trimmed.length < 2 || !cityGroupId) {
@@ -6260,7 +6438,7 @@ function buildSchedule(wasteTypes, places, selectedPlaceId) {
6260
6438
  dayOfWeek: dayIndex,
6261
6439
  wasteTypeId: day.wasteTypeId,
6262
6440
  color: typeof color === "string" && color.trim().length > 0 ? color : "#7C7C7C",
6263
- biweekly: day.biweekly,
6441
+ everyWeeks: Math.max(1, Number(day.everyWeeks) || 1),
6264
6442
  startDate: day.startDate
6265
6443
  });
6266
6444
  }
@@ -6274,14 +6452,13 @@ function computeWasteTypesForDay(day, year, month, schedule, exceptions) {
6274
6452
  const daySchedules = schedule.filter((s) => s.dayOfWeek === mondayBasedDay);
6275
6453
  const wasteTypes = [];
6276
6454
  for (const s of daySchedules) {
6277
- if (s.biweekly && s.startDate) {
6455
+ const everyWeeks = Math.max(1, Number(s.everyWeeks) || 1);
6456
+ if (s.startDate) {
6278
6457
  const weeksSinceStart = getWeeksSinceStart(s.startDate, date);
6279
- if (weeksSinceStart >= 0 && weeksSinceStart % 2 === 0) {
6280
- wasteTypes.push({ wasteTypeId: s.wasteTypeId, color: s.color });
6281
- }
6282
- } else if (!s.biweekly) {
6283
- wasteTypes.push({ wasteTypeId: s.wasteTypeId, color: s.color });
6458
+ if (weeksSinceStart < 0) continue;
6459
+ if (everyWeeks > 1 && weeksSinceStart % everyWeeks !== 0) continue;
6284
6460
  }
6461
+ wasteTypes.push({ wasteTypeId: s.wasteTypeId, color: s.color });
6285
6462
  }
6286
6463
  const filtered = [];
6287
6464
  for (const wt of wasteTypes) {
@@ -6409,7 +6586,7 @@ var styles22 = StyleSheet23.create({
6409
6586
  // src/components/next-collection/NextCollection.tsx
6410
6587
  import {
6411
6588
  Dimensions as Dimensions6,
6412
- Platform as Platform4,
6589
+ Platform as Platform6,
6413
6590
  Pressable as Pressable11,
6414
6591
  StyleSheet as StyleSheet24,
6415
6592
  Text as Text20,
@@ -6429,7 +6606,7 @@ import Animated2, {
6429
6606
  useSharedValue
6430
6607
  } from "react-native-reanimated";
6431
6608
  import { ChevronLeftIcon as ChevronLeftIcon2, ChevronRightIcon } from "lucide-react-native";
6432
- import { useCallback as useCallback11, useEffect as useEffect13, useMemo as useMemo17, useRef as useRef5, useState as useState20 } from "react";
6609
+ import { useCallback as useCallback11, useEffect as useEffect14, useMemo as useMemo17, useRef as useRef6, useState as useState20 } from "react";
6433
6610
 
6434
6611
  // src/navigation/NavigationContext.tsx
6435
6612
  import {
@@ -6514,7 +6691,7 @@ function CollectionSlide({
6514
6691
  width: cardWidth,
6515
6692
  height: cardHeight,
6516
6693
  marginRight: isLast ? 0 : CARD_GAP,
6517
- ...Platform4.OS === "web" ? { scrollSnapAlign: "center", scrollSnapStop: "always" } : null
6694
+ ...Platform6.OS === "web" ? { scrollSnapAlign: "center", scrollSnapStop: "always" } : null
6518
6695
  },
6519
6696
  animatedStyle
6520
6697
  ],
@@ -6681,13 +6858,13 @@ function NextCollection({
6681
6858
  const { collectionsForDay, dateLabel } = useNextCollection({
6682
6859
  dateOffset: offset
6683
6860
  });
6684
- useEffect13(() => {
6861
+ useEffect14(() => {
6685
6862
  setOffset(Math.trunc(dayOffset));
6686
6863
  }, [dayOffset]);
6687
6864
  const [selectedWasteTypeId, setSelectedWasteTypeId] = useState20(null);
6688
- const listRef = useRef5(null);
6865
+ const listRef = useRef6(null);
6689
6866
  const scrollX = useSharedValue(0);
6690
- const lastSnappedIndex = useRef5(0);
6867
+ const lastSnappedIndex = useRef6(0);
6691
6868
  const screenWidth = Dimensions6.get("window").width;
6692
6869
  const cardWidth = Math.round(screenWidth - SIDE_INSET * 2);
6693
6870
  const cardHeight = Math.round(cardWidth * CARD_ASPECT);
@@ -6828,8 +7005,8 @@ function NextCollection({
6828
7005
  horizontal: true,
6829
7006
  showsHorizontalScrollIndicator: false,
6830
7007
  decelerationRate: "fast",
6831
- snapToInterval: Platform4.OS === "web" ? void 0 : snapInterval,
6832
- snapToOffsets: Platform4.OS === "web" ? void 0 : snapOffsets,
7008
+ snapToInterval: Platform6.OS === "web" ? void 0 : snapInterval,
7009
+ snapToOffsets: Platform6.OS === "web" ? void 0 : snapOffsets,
6833
7010
  snapToAlignment: "center",
6834
7011
  disableIntervalMomentum: true,
6835
7012
  bounces: false,
@@ -6843,7 +7020,7 @@ function NextCollection({
6843
7020
  },
6844
7021
  style: [
6845
7022
  { height: cardHeight },
6846
- Platform4.OS === "web" ? {
7023
+ Platform6.OS === "web" ? {
6847
7024
  scrollSnapType: "x mandatory",
6848
7025
  WebkitOverflowScrolling: "touch"
6849
7026
  } : null
@@ -7386,15 +7563,15 @@ function Image10(props) {
7386
7563
  // src/components/locations-map/LocationsMapView.web.tsx
7387
7564
  import {
7388
7565
  createElement,
7389
- useEffect as useEffect15,
7566
+ useEffect as useEffect16,
7390
7567
  useMemo as useMemo19,
7391
- useRef as useRef6,
7568
+ useRef as useRef7,
7392
7569
  useState as useState23
7393
7570
  } from "react";
7394
7571
  import { StyleSheet as StyleSheet28, Text as Text23, View as View27 } from "react-native";
7395
7572
 
7396
7573
  // src/hooks/useLocations.ts
7397
- import { useCallback as useCallback12, useEffect as useEffect14, useMemo as useMemo18, useState as useState22 } from "react";
7574
+ import { useCallback as useCallback12, useEffect as useEffect15, useMemo as useMemo18, useState as useState22 } from "react";
7398
7575
  import { MAX_PAGE_SIZE } from "@wasto/sdk";
7399
7576
  var PAGE_SIZE = MAX_PAGE_SIZE;
7400
7577
  function asArray2(res) {
@@ -7455,7 +7632,7 @@ function useLocations() {
7455
7632
  setIsLoading(false);
7456
7633
  }
7457
7634
  }, [appData, client.public.cities, selectedCityId, useShared]);
7458
- useEffect14(() => {
7635
+ useEffect15(() => {
7459
7636
  if (useShared) return;
7460
7637
  void fetchLocations();
7461
7638
  }, [fetchLocations, useShared]);
@@ -7535,11 +7712,11 @@ function LocationsMapView({
7535
7712
  selectedId,
7536
7713
  onSelect
7537
7714
  }) {
7538
- const containerRef = useRef6(null);
7539
- const mapRef = useRef6(null);
7540
- const maplibreRef = useRef6(null);
7541
- const markersRef = useRef6([]);
7542
- const onSelectRef = useRef6(onSelect);
7715
+ const containerRef = useRef7(null);
7716
+ const mapRef = useRef7(null);
7717
+ const maplibreRef = useRef7(null);
7718
+ const markersRef = useRef7([]);
7719
+ const onSelectRef = useRef7(onSelect);
7543
7720
  const [mapReady, setMapReady] = useState23(false);
7544
7721
  const [mapError, setMapError] = useState23(null);
7545
7722
  const safeCenter = useMemo19(() => {
@@ -7550,10 +7727,10 @@ function LocationsMapView({
7550
7727
  () => locations.filter((loc) => isValidLatLon(loc.lat, loc.lon)),
7551
7728
  [locations]
7552
7729
  );
7553
- useEffect15(() => {
7730
+ useEffect16(() => {
7554
7731
  onSelectRef.current = onSelect;
7555
7732
  }, [onSelect]);
7556
- useEffect15(() => {
7733
+ useEffect16(() => {
7557
7734
  let cancelled = false;
7558
7735
  let resizeObserver = null;
7559
7736
  async function init() {
@@ -7625,7 +7802,7 @@ function LocationsMapView({
7625
7802
  setMapReady(false);
7626
7803
  };
7627
7804
  }, []);
7628
- useEffect15(() => {
7805
+ useEffect16(() => {
7629
7806
  if (!mapReady) return;
7630
7807
  const map = mapRef.current;
7631
7808
  const maplibregl = maplibreRef.current;
@@ -7650,7 +7827,7 @@ function LocationsMapView({
7650
7827
  () => validLocations.map((l) => l.id).join("|"),
7651
7828
  [validLocations]
7652
7829
  );
7653
- useEffect15(() => {
7830
+ useEffect16(() => {
7654
7831
  if (!mapReady) return;
7655
7832
  const map = mapRef.current;
7656
7833
  const maplibregl = maplibreRef.current;
@@ -7672,7 +7849,7 @@ function LocationsMapView({
7672
7849
  for (const loc of visible) bounds.extend([loc.lon, loc.lat]);
7673
7850
  map.fitBounds(bounds, { padding: 56, maxZoom: 13, duration: 350 });
7674
7851
  }, [locationsKey, mapReady]);
7675
- useEffect15(() => {
7852
+ useEffect16(() => {
7676
7853
  if (!mapReady) return;
7677
7854
  const map = mapRef.current;
7678
7855
  if (!map || !selectedId) return;
@@ -7724,7 +7901,7 @@ var styles27 = StyleSheet28.create({
7724
7901
  });
7725
7902
 
7726
7903
  // src/components/locations-map/LocationsMapShell.tsx
7727
- import { useEffect as useEffect17, useMemo as useMemo21, useRef as useRef7, useState as useState25 } from "react";
7904
+ import { useEffect as useEffect18, useMemo as useMemo21, useRef as useRef8, useState as useState25 } from "react";
7728
7905
  import {
7729
7906
  ActivityIndicator as ActivityIndicator11,
7730
7907
  Pressable as Pressable14,
@@ -7743,7 +7920,7 @@ import Animated5, {
7743
7920
  } from "react-native-reanimated";
7744
7921
 
7745
7922
  // src/components/locations-map/LocationSheet.tsx
7746
- import { Linking as Linking3, Platform as Platform5, Pressable as Pressable12, ScrollView as ScrollView9, Share, StyleSheet as StyleSheet29, Text as Text24, View as View28 } from "react-native";
7923
+ import { Linking as Linking3, Platform as Platform7, Pressable as Pressable12, ScrollView as ScrollView9, Share, StyleSheet as StyleSheet29, Text as Text24, View as View28 } from "react-native";
7747
7924
  import {
7748
7925
  ChevronUp,
7749
7926
  Clock,
@@ -7752,7 +7929,7 @@ import {
7752
7929
  Phone,
7753
7930
  X as X4
7754
7931
  } from "lucide-react-native";
7755
- import { useEffect as useEffect16, useState as useState24 } from "react";
7932
+ import { useEffect as useEffect17, useState as useState24 } from "react";
7756
7933
  import { Gesture, GestureDetector } from "react-native-gesture-handler";
7757
7934
  import Animated4, {
7758
7935
  Easing,
@@ -7770,7 +7947,7 @@ var DISMISS_V = 900;
7770
7947
  async function copyText(value) {
7771
7948
  try {
7772
7949
  const webNav = globalThis.navigator;
7773
- if (Platform5.OS === "web" && webNav?.clipboard?.writeText) {
7950
+ if (Platform7.OS === "web" && webNav?.clipboard?.writeText) {
7774
7951
  await webNav.clipboard.writeText(value);
7775
7952
  return;
7776
7953
  }
@@ -7791,7 +7968,7 @@ function LocationSheet({
7791
7968
  const opacity = useSharedValue2(0);
7792
7969
  const hoursProgress = useSharedValue2(0);
7793
7970
  const hoursHeight = useSharedValue2(0);
7794
- useEffect16(() => {
7971
+ useEffect17(() => {
7795
7972
  setHoursOpen(false);
7796
7973
  hoursProgress.value = 0;
7797
7974
  translateY.value = 48;
@@ -8118,19 +8295,33 @@ var SYSTEM_ROUTES = {
8118
8295
 
8119
8296
  // src/components/header/Header.tsx
8120
8297
  import { Fragment as Fragment11, jsx as jsx41, jsxs as jsxs26 } from "react/jsx-runtime";
8298
+ var DEFAULT_HEADER_ACTIONS = [
8299
+ {
8300
+ id: "notifications",
8301
+ type: "action",
8302
+ slot: "right",
8303
+ icon: "bell",
8304
+ action: "navigate",
8305
+ href: SYSTEM_ROUTES.notifications
8306
+ },
8307
+ {
8308
+ id: "profile",
8309
+ type: "action",
8310
+ slot: "right",
8311
+ icon: "person",
8312
+ action: "navigate",
8313
+ href: SYSTEM_ROUTES.profile
8314
+ }
8315
+ ];
8121
8316
  function resolveLogoUri(apiUrl, el) {
8122
- if (el.sourceType === "media") {
8317
+ const url = (el.url || "").trim();
8318
+ if (url) return url;
8319
+ if (el.sourceType === "media" || el.mediaId) {
8123
8320
  return publicMediaUrl(apiUrl, el.mediaId);
8124
8321
  }
8125
- const url = (el.url || "").trim();
8126
- return url || null;
8322
+ return null;
8127
8323
  }
8128
- function HeaderLogo({
8129
- element
8130
- }) {
8131
- const { apiUrl } = useWasto();
8132
- const uri = resolveLogoUri(apiUrl, element);
8133
- if (!uri) return null;
8324
+ function HeaderLogoImage({ uri }) {
8134
8325
  return /* @__PURE__ */ jsx41(
8135
8326
  Image11,
8136
8327
  {
@@ -8141,6 +8332,22 @@ function HeaderLogo({
8141
8332
  }
8142
8333
  );
8143
8334
  }
8335
+ function HeaderLogo({
8336
+ element
8337
+ }) {
8338
+ const { apiUrl } = useWasto();
8339
+ const uri = resolveLogoUri(apiUrl, element);
8340
+ if (!uri) return null;
8341
+ return /* @__PURE__ */ jsx41(HeaderLogoImage, { uri });
8342
+ }
8343
+ function CityLogoFallback() {
8344
+ const { apiUrl } = useWasto();
8345
+ const appData = useOptionalAppData();
8346
+ const logoMediaId = typeof appData?.city?.logoMediaId === "string" ? appData.city.logoMediaId : null;
8347
+ const uri = publicMediaUrl(apiUrl, logoMediaId);
8348
+ if (!uri) return null;
8349
+ return /* @__PURE__ */ jsx41(HeaderLogoImage, { uri });
8350
+ }
8144
8351
  function HeaderActionButton({
8145
8352
  onPress,
8146
8353
  accessibilityLabel,
@@ -8175,9 +8382,13 @@ function Header({
8175
8382
  () => options.title ?? route.name,
8176
8383
  [options.title, route.name]
8177
8384
  );
8178
- const elements = headerConfig?.elements ?? [];
8179
- const hasCustom = elements.length > 0;
8385
+ const hasExplicitConfig = headerConfig != null;
8386
+ const elements = useMemo20(() => {
8387
+ const raw = headerConfig?.elements ?? [];
8388
+ return raw.filter((el) => el.type !== "title");
8389
+ }, [headerConfig]);
8180
8390
  const hasCustomActions = elements.some((el) => el.type === "action");
8391
+ const hasLogo = elements.some((el) => el.type === "logo");
8181
8392
  const bySlot = useMemo20(() => {
8182
8393
  const left = [];
8183
8394
  const center = [];
@@ -8202,8 +8413,7 @@ function Header({
8202
8413
  return /* @__PURE__ */ jsx41(HeaderLogo, { element: el }, el.id);
8203
8414
  }
8204
8415
  if (el.type === "title") {
8205
- const text = el.useScreenTitle !== false ? screenTitle : (el.text || "").trim() || screenTitle;
8206
- return /* @__PURE__ */ jsx41(Title, { text, level: "1" }, el.id);
8416
+ return null;
8207
8417
  }
8208
8418
  const onPress = async () => {
8209
8419
  await hapticSelection();
@@ -8282,7 +8492,7 @@ function Header({
8282
8492
  topInset
8283
8493
  ],
8284
8494
  pointerEvents: "box-none",
8285
- children: /* @__PURE__ */ jsx41(View29, { style: styles29.header, pointerEvents: "box-none", children: hasCustom ? /* @__PURE__ */ jsxs26(Fragment11, { children: [
8495
+ children: /* @__PURE__ */ jsx41(View29, { style: styles29.header, pointerEvents: "box-none", children: hasExplicitConfig ? /* @__PURE__ */ jsxs26(Fragment11, { children: [
8286
8496
  /* @__PURE__ */ jsxs26(View29, { style: styles29.slotLeft, pointerEvents: "box-none", children: [
8287
8497
  showBack ? /* @__PURE__ */ jsx41(
8288
8498
  HeaderActionButton,
@@ -8300,7 +8510,8 @@ function Header({
8300
8510
  )
8301
8511
  }
8302
8512
  ) : null,
8303
- bySlot.left.map(renderElement)
8513
+ bySlot.left.map(renderElement),
8514
+ !hasLogo ? /* @__PURE__ */ jsx41(CityLogoFallback, {}) : null
8304
8515
  ] }),
8305
8516
  /* @__PURE__ */ jsx41(
8306
8517
  View29,
@@ -8332,6 +8543,7 @@ function Header({
8332
8543
  )
8333
8544
  }
8334
8545
  ) : null,
8546
+ /* @__PURE__ */ jsx41(CityLogoFallback, {}),
8335
8547
  /* @__PURE__ */ jsx41(Title, { text: screenTitle, level: "1" })
8336
8548
  ] }),
8337
8549
  /* @__PURE__ */ jsx41(View29, { style: styles29.actions, children: defaultActions })
@@ -8356,9 +8568,9 @@ var styles29 = StyleSheet30.create({
8356
8568
  alignItems: "center",
8357
8569
  justifyContent: "space-between",
8358
8570
  paddingHorizontal: SPACE.pageX,
8359
- paddingVertical: 12,
8571
+ paddingVertical: 6,
8360
8572
  gap: 10,
8361
- minHeight: 56
8573
+ minHeight: 44
8362
8574
  },
8363
8575
  left: {
8364
8576
  flexDirection: "row",
@@ -8413,8 +8625,25 @@ var styles29 = StyleSheet30.create({
8413
8625
  }
8414
8626
  });
8415
8627
 
8628
+ // src/contexts/HeaderConfigContext.tsx
8629
+ import {
8630
+ createContext as createContext8,
8631
+ useContext as useContext9
8632
+ } from "react";
8633
+ import { jsx as jsx42 } from "react/jsx-runtime";
8634
+ var HeaderConfigContext = createContext8(null);
8635
+ function HeaderConfigProvider({
8636
+ value,
8637
+ children
8638
+ }) {
8639
+ return /* @__PURE__ */ jsx42(HeaderConfigContext.Provider, { value, children });
8640
+ }
8641
+ function useHeaderConfig() {
8642
+ return useContext9(HeaderConfigContext);
8643
+ }
8644
+
8416
8645
  // src/components/locations-map/LocationsMapShell.tsx
8417
- import { Fragment as Fragment12, jsx as jsx42, jsxs as jsxs27 } from "react/jsx-runtime";
8646
+ import { Fragment as Fragment12, jsx as jsx43, jsxs as jsxs27 } from "react/jsx-runtime";
8418
8647
  var CATEGORIES = Object.keys(LOCATION_CATEGORY_META);
8419
8648
  var NOOP_NAV = { canGoBack: () => false, goBack: () => void 0 };
8420
8649
  var PANEL_OPEN = { duration: 300, easing: Easing2.out(Easing2.cubic) };
@@ -8427,7 +8656,7 @@ function RoundCtrl({
8427
8656
  backgroundColor,
8428
8657
  borderColor
8429
8658
  }) {
8430
- return /* @__PURE__ */ jsx42(
8659
+ return /* @__PURE__ */ jsx43(
8431
8660
  Pressable14,
8432
8661
  {
8433
8662
  onPress,
@@ -8453,9 +8682,9 @@ function FilterPanel({
8453
8682
  const t = resolveTheme(theme);
8454
8683
  const progress = useSharedValue3(0);
8455
8684
  const widthSv = useSharedValue3(0);
8456
- const closing = useRef7(false);
8457
- const closeTimer = useRef7(null);
8458
- useEffect17(() => {
8685
+ const closing = useRef8(false);
8686
+ const closeTimer = useRef8(null);
8687
+ useEffect18(() => {
8459
8688
  return () => {
8460
8689
  if (closeTimer.current) clearTimeout(closeTimer.current);
8461
8690
  };
@@ -8476,7 +8705,7 @@ function FilterPanel({
8476
8705
  ]
8477
8706
  };
8478
8707
  }, []);
8479
- return /* @__PURE__ */ jsx42(
8708
+ return /* @__PURE__ */ jsx43(
8480
8709
  Animated5.View,
8481
8710
  {
8482
8711
  onLayout: (event) => {
@@ -8497,8 +8726,8 @@ function FilterPanel({
8497
8726
  ],
8498
8727
  children: [
8499
8728
  /* @__PURE__ */ jsxs27(View30, { style: styles30.filterPanelHead, children: [
8500
- /* @__PURE__ */ jsx42(Text25, { style: [styles30.filterPanelTitle, { color: theme.colors.onSurface }], children: title }),
8501
- /* @__PURE__ */ jsx42(
8729
+ /* @__PURE__ */ jsx43(Text25, { style: [styles30.filterPanelTitle, { color: theme.colors.onSurface }], children: title }),
8730
+ /* @__PURE__ */ jsx43(
8502
8731
  Pressable14,
8503
8732
  {
8504
8733
  onPress: close,
@@ -8512,7 +8741,7 @@ function FilterPanel({
8512
8741
  borderRadius: t.radii.pill
8513
8742
  }
8514
8743
  ],
8515
- children: /* @__PURE__ */ jsx42(X5, { size: 16, color: theme.colors.onSurface })
8744
+ children: /* @__PURE__ */ jsx43(X5, { size: 16, color: theme.colors.onSurface })
8516
8745
  }
8517
8746
  )
8518
8747
  ] }),
@@ -8527,16 +8756,26 @@ function LocationsMapShell({
8527
8756
  fullScreen = false,
8528
8757
  showFilters = true,
8529
8758
  overlayHeader = false,
8530
- overlayTitle = "Carte",
8759
+ headerConfig: headerConfigProp,
8531
8760
  MapCanvas
8532
8761
  }) {
8533
8762
  const { theme } = useTheme();
8534
8763
  const t = resolveTheme(theme);
8535
8764
  const themedStyles = createThemedStyles15(theme);
8765
+ const layoutHeaderConfig = useHeaderConfig();
8536
8766
  const { locations, isLoading, error, center } = useLocations();
8537
8767
  const [filters, setFilters] = useState25(/* @__PURE__ */ new Set());
8538
8768
  const [selected, setSelected] = useState25(null);
8539
8769
  const [filtersOpen, setFiltersOpen] = useState25(false);
8770
+ const overlayHeaderConfig = useMemo21(() => {
8771
+ const raw = headerConfigProp ?? layoutHeaderConfig;
8772
+ if (raw?.elements?.length) {
8773
+ return {
8774
+ elements: raw.elements.filter((el) => el.type !== "title")
8775
+ };
8776
+ }
8777
+ return { elements: DEFAULT_HEADER_ACTIONS.map((a) => ({ ...a })) };
8778
+ }, [headerConfigProp, layoutHeaderConfig]);
8540
8779
  const toggle = (category) => {
8541
8780
  setFilters((prev) => {
8542
8781
  const next = new Set(prev);
@@ -8558,7 +8797,7 @@ function LocationsMapShell({
8558
8797
  };
8559
8798
  const roundRadius = t.radii.pill;
8560
8799
  return /* @__PURE__ */ jsxs27(View30, { style: [styles30.wrap, fullScreen && styles30.fullScreen], children: [
8561
- /* @__PURE__ */ jsx42(
8800
+ /* @__PURE__ */ jsx43(
8562
8801
  View30,
8563
8802
  {
8564
8803
  style: [
@@ -8567,10 +8806,10 @@ function LocationsMapShell({
8567
8806
  fullScreen ? styles30.mapShellFull : styles30.mapShellFixed
8568
8807
  ],
8569
8808
  children: isLoading ? /* @__PURE__ */ jsxs27(View30, { style: styles30.center, children: [
8570
- /* @__PURE__ */ jsx42(ActivityIndicator11, { color: theme.colors.primary }),
8571
- /* @__PURE__ */ jsx42(Text25, { style: themedStyles.muted, children: "Chargement de la carte\u2026" })
8809
+ /* @__PURE__ */ jsx43(ActivityIndicator11, { color: theme.colors.primary }),
8810
+ /* @__PURE__ */ jsx43(Text25, { style: themedStyles.muted, children: "Chargement de la carte\u2026" })
8572
8811
  ] }) : /* @__PURE__ */ jsxs27(Fragment12, { children: [
8573
- /* @__PURE__ */ jsx42(
8812
+ /* @__PURE__ */ jsx43(
8574
8813
  MapCanvas,
8575
8814
  {
8576
8815
  locations: visible,
@@ -8579,19 +8818,20 @@ function LocationsMapShell({
8579
8818
  onSelect: selectLocation
8580
8819
  }
8581
8820
  ),
8582
- error ? /* @__PURE__ */ jsx42(View30, { style: [styles30.center, styles30.mapOverlayMessage], pointerEvents: "none", children: /* @__PURE__ */ jsx42(Text25, { style: { color: theme.colors.error, textAlign: "center" }, children: error }) }) : null,
8583
- !error && visible.length === 0 ? /* @__PURE__ */ jsx42(View30, { style: [styles30.center, styles30.mapOverlayMessage], pointerEvents: "none", children: /* @__PURE__ */ jsx42(Text25, { style: themedStyles.muted, children: "Aucun point \xE0 afficher." }) }) : null
8821
+ error ? /* @__PURE__ */ jsx43(View30, { style: [styles30.center, styles30.mapOverlayMessage], pointerEvents: "none", children: /* @__PURE__ */ jsx43(Text25, { style: { color: theme.colors.error, textAlign: "center" }, children: error }) }) : null,
8822
+ !error && visible.length === 0 ? /* @__PURE__ */ jsx43(View30, { style: [styles30.center, styles30.mapOverlayMessage], pointerEvents: "none", children: /* @__PURE__ */ jsx43(Text25, { style: themedStyles.muted, children: "Aucun point \xE0 afficher." }) }) : null
8584
8823
  ] })
8585
8824
  }
8586
8825
  ),
8587
8826
  /* @__PURE__ */ jsxs27(View30, { style: styles30.topOverlay, pointerEvents: "box-none", children: [
8588
- overlayHeader ? /* @__PURE__ */ jsx42(
8827
+ overlayHeader ? /* @__PURE__ */ jsx43(
8589
8828
  Header,
8590
8829
  {
8591
8830
  overlay: true,
8592
- options: { title: overlayTitle, headerBackVisible: false },
8593
- route: { name: overlayTitle },
8594
- navigation: NOOP_NAV
8831
+ options: { headerBackVisible: false },
8832
+ route: { name: "map" },
8833
+ navigation: NOOP_NAV,
8834
+ headerConfig: overlayHeaderConfig
8595
8835
  }
8596
8836
  ) : null,
8597
8837
  showFilters ? /* @__PURE__ */ jsxs27(View30, { style: styles30.filtersOverlay, pointerEvents: "box-none", children: [
@@ -8603,7 +8843,7 @@ function LocationsMapShell({
8603
8843
  style: styles30.chipScrollView,
8604
8844
  contentContainerStyle: styles30.chipScroll,
8605
8845
  children: [
8606
- /* @__PURE__ */ jsx42(
8846
+ /* @__PURE__ */ jsx43(
8607
8847
  RoundCtrl,
8608
8848
  {
8609
8849
  label: "Ouvrir les filtres",
@@ -8611,13 +8851,13 @@ function LocationsMapShell({
8611
8851
  radius: roundRadius,
8612
8852
  backgroundColor: theme.colors.surface,
8613
8853
  borderColor: theme.colors.border,
8614
- children: /* @__PURE__ */ jsx42(ChevronRight, { size: 16, color: theme.colors.onSurface })
8854
+ children: /* @__PURE__ */ jsx43(ChevronRight, { size: 16, color: theme.colors.onSurface })
8615
8855
  }
8616
8856
  ),
8617
8857
  selectedCategories.map((category) => {
8618
8858
  const meta = LOCATION_CATEGORY_META[category];
8619
8859
  const fg = getContrastColor(meta.color);
8620
- return /* @__PURE__ */ jsx42(
8860
+ return /* @__PURE__ */ jsx43(
8621
8861
  Pressable14,
8622
8862
  {
8623
8863
  onPress: () => toggle(category),
@@ -8628,12 +8868,12 @@ function LocationsMapShell({
8628
8868
  borderRadius: t.radii.pill
8629
8869
  }
8630
8870
  ],
8631
- children: /* @__PURE__ */ jsx42(Text25, { style: [styles30.chipText, { color: fg }], children: meta.label })
8871
+ children: /* @__PURE__ */ jsx43(Text25, { style: [styles30.chipText, { color: fg }], children: meta.label })
8632
8872
  },
8633
8873
  category
8634
8874
  );
8635
8875
  }),
8636
- /* @__PURE__ */ jsx42(
8876
+ /* @__PURE__ */ jsx43(
8637
8877
  RoundCtrl,
8638
8878
  {
8639
8879
  label: "Effacer les filtres",
@@ -8641,7 +8881,7 @@ function LocationsMapShell({
8641
8881
  radius: roundRadius,
8642
8882
  backgroundColor: theme.colors.surface,
8643
8883
  borderColor: theme.colors.border,
8644
- children: /* @__PURE__ */ jsx42(X5, { size: 16, color: theme.colors.onSurface })
8884
+ children: /* @__PURE__ */ jsx43(X5, { size: 16, color: theme.colors.onSurface })
8645
8885
  }
8646
8886
  )
8647
8887
  ]
@@ -8656,12 +8896,12 @@ function LocationsMapShell({
8656
8896
  { borderRadius: t.radii.pill }
8657
8897
  ],
8658
8898
  children: [
8659
- /* @__PURE__ */ jsx42(Text25, { style: [styles30.filterTriggerText, { color: theme.colors.onSurface }], children: filterLabel }),
8660
- /* @__PURE__ */ jsx42(ChevronRight, { size: 16, color: theme.colors.onSurface })
8899
+ /* @__PURE__ */ jsx43(Text25, { style: [styles30.filterTriggerText, { color: theme.colors.onSurface }], children: filterLabel }),
8900
+ /* @__PURE__ */ jsx43(ChevronRight, { size: 16, color: theme.colors.onSurface })
8661
8901
  ]
8662
8902
  }
8663
8903
  ),
8664
- filtersOpen ? /* @__PURE__ */ jsx42(FilterPanel, { title: filterLabel, onClose: () => setFiltersOpen(false), children: /* @__PURE__ */ jsx42(View30, { style: styles30.filterList, children: CATEGORIES.map((category) => {
8904
+ filtersOpen ? /* @__PURE__ */ jsx43(FilterPanel, { title: filterLabel, onClose: () => setFiltersOpen(false), children: /* @__PURE__ */ jsx43(View30, { style: styles30.filterList, children: CATEGORIES.map((category) => {
8665
8905
  const meta = LOCATION_CATEGORY_META[category];
8666
8906
  const active2 = filters.has(category);
8667
8907
  const bg = active2 ? meta.color : theme.colors.background;
@@ -8678,8 +8918,8 @@ function LocationsMapShell({
8678
8918
  }
8679
8919
  ],
8680
8920
  children: [
8681
- /* @__PURE__ */ jsx42(MapPin4, { size: 16, color: fg }),
8682
- /* @__PURE__ */ jsx42(Text25, { style: [styles30.filterRowText, { color: fg }], children: meta.label })
8921
+ /* @__PURE__ */ jsx43(MapPin4, { size: 16, color: fg }),
8922
+ /* @__PURE__ */ jsx43(Text25, { style: [styles30.filterRowText, { color: fg }], children: meta.label })
8683
8923
  ]
8684
8924
  },
8685
8925
  category
@@ -8687,7 +8927,7 @@ function LocationsMapShell({
8687
8927
  }) }) }) : null
8688
8928
  ] }) : null
8689
8929
  ] }),
8690
- selected ? /* @__PURE__ */ jsx42(View30, { style: styles30.sheetOverlay, pointerEvents: "box-none", children: /* @__PURE__ */ jsx42(LocationSheet, { location: selected, onClose: () => setSelected(null) }) }) : null
8930
+ selected ? /* @__PURE__ */ jsx43(View30, { style: styles30.sheetOverlay, pointerEvents: "box-none", children: /* @__PURE__ */ jsx43(LocationSheet, { location: selected, onClose: () => setSelected(null) }) }) : null
8691
8931
  ] });
8692
8932
  }
8693
8933
  var createThemedStyles15 = (theme) => StyleSheet31.create({
@@ -8850,15 +9090,20 @@ var styles30 = StyleSheet31.create({
8850
9090
  });
8851
9091
 
8852
9092
  // src/components/locations-map/LocationsMap.tsx
8853
- import { jsx as jsx43 } from "react/jsx-runtime";
9093
+ import { jsx as jsx44 } from "react/jsx-runtime";
8854
9094
  function LocationsMap(props) {
8855
- return /* @__PURE__ */ jsx43(LocationsMapShell, { ...props, MapCanvas: LocationsMapView });
9095
+ return /* @__PURE__ */ jsx44(LocationsMapShell, { ...props, MapCanvas: LocationsMapView });
8856
9096
  }
8857
9097
 
8858
9098
  // src/components/page/Page.tsx
8859
- import { useCallback as useCallback13, useState as useState26 } from "react";
9099
+ import {
9100
+ useCallback as useCallback13,
9101
+ useContext as useContext10,
9102
+ useState as useState26
9103
+ } from "react";
8860
9104
  import { RefreshControl, ScrollView as ScrollView11, StyleSheet as StyleSheet32, View as View31 } from "react-native";
8861
- import { jsx as jsx44 } from "react/jsx-runtime";
9105
+ import { HeaderHeightContext } from "@react-navigation/elements";
9106
+ import { jsx as jsx45 } from "react/jsx-runtime";
8862
9107
  function Page({
8863
9108
  children,
8864
9109
  scroll = true,
@@ -8867,7 +9112,9 @@ function Page({
8867
9112
  const { theme } = useTheme();
8868
9113
  const t = resolveTheme(theme);
8869
9114
  const themedStyles = createThemedStyles16(theme);
8870
- const topInset = useSafeAreaPadding(["top"]);
9115
+ const headerHeight = useContext10(HeaderHeightContext);
9116
+ const hasNavHeader = typeof headerHeight === "number" && headerHeight > 0;
9117
+ const topInset = useSafeAreaPadding(hasNavHeader ? [] : ["top"]);
8871
9118
  const appData = useOptionalAppData();
8872
9119
  const [refreshing, setRefreshing] = useState26(false);
8873
9120
  const enableRefresh = pullToRefresh ?? scroll;
@@ -8880,14 +9127,14 @@ function Page({
8880
9127
  setRefreshing(false);
8881
9128
  }
8882
9129
  }, [appData]);
8883
- return /* @__PURE__ */ jsx44(View31, { style: [styles31.root, themedStyles.root, topInset], children: scroll ? /* @__PURE__ */ jsx44(
9130
+ return /* @__PURE__ */ jsx45(View31, { style: [styles31.root, themedStyles.root, topInset], children: scroll ? /* @__PURE__ */ jsx45(
8884
9131
  ScrollView11,
8885
9132
  {
8886
9133
  style: styles31.scroll,
8887
9134
  contentContainerStyle: styles31.scrollContent,
8888
9135
  keyboardShouldPersistTaps: "handled",
8889
9136
  showsVerticalScrollIndicator: false,
8890
- refreshControl: enableRefresh && appData ? /* @__PURE__ */ jsx44(
9137
+ refreshControl: enableRefresh && appData ? /* @__PURE__ */ jsx45(
8891
9138
  RefreshControl,
8892
9139
  {
8893
9140
  refreshing,
@@ -8900,7 +9147,7 @@ function Page({
8900
9147
  ) : void 0,
8901
9148
  children
8902
9149
  }
8903
- ) : /* @__PURE__ */ jsx44(View31, { style: styles31.fill, children }) });
9150
+ ) : /* @__PURE__ */ jsx45(View31, { style: styles31.fill, children }) });
8904
9151
  }
8905
9152
  var createThemedStyles16 = (theme) => StyleSheet32.create({
8906
9153
  root: {
@@ -8927,7 +9174,7 @@ var styles31 = StyleSheet32.create({
8927
9174
 
8928
9175
  // src/components/parapraph/Paragraph.tsx
8929
9176
  import { StyleSheet as StyleSheet33, Text as Text26, View as View32 } from "react-native";
8930
- import { jsx as jsx45 } from "react/jsx-runtime";
9177
+ import { jsx as jsx46 } from "react/jsx-runtime";
8931
9178
  function justifyForVertical2(align) {
8932
9179
  if (align === "middle") return "center";
8933
9180
  if (align === "bottom") return "flex-end";
@@ -8946,11 +9193,11 @@ function Paragraph({
8946
9193
  const { theme } = useTheme();
8947
9194
  const themedStyles = createThemedStyles17(theme);
8948
9195
  const textAlign = textAlignFor2(alignHorizontal);
8949
- const content = /* @__PURE__ */ jsx45(Text26, { style: [styles32.text, themedStyles.text, { textAlign }, style], children: text });
9196
+ const content = /* @__PURE__ */ jsx46(Text26, { style: [styles32.text, themedStyles.text, { textAlign }, style], children: text });
8950
9197
  if (!alignVertical || alignVertical === "top") {
8951
9198
  return content;
8952
9199
  }
8953
- return /* @__PURE__ */ jsx45(View32, { style: [styles32.alignWrap, { justifyContent: justifyForVertical2(alignVertical) }], children: content });
9200
+ return /* @__PURE__ */ jsx46(View32, { style: [styles32.alignWrap, { justifyContent: justifyForVertical2(alignVertical) }], children: content });
8954
9201
  }
8955
9202
  var createThemedStyles17 = (theme) => StyleSheet33.create({
8956
9203
  text: {
@@ -9018,7 +9265,7 @@ function useRecyclingInfo(options = {}) {
9018
9265
 
9019
9266
  // src/components/recycling-info/RecyclingInfo.tsx
9020
9267
  import { useState as useState27 } from "react";
9021
- import { Fragment as Fragment13, jsx as jsx46, jsxs as jsxs28 } from "react/jsx-runtime";
9268
+ import { Fragment as Fragment13, jsx as jsx47, jsxs as jsxs28 } from "react/jsx-runtime";
9022
9269
  function RecyclingInfo({}) {
9023
9270
  const { recyclingInfos } = useRecyclingInfo();
9024
9271
  const { theme } = useTheme();
@@ -9032,7 +9279,7 @@ function RecyclingInfo({}) {
9032
9279
  };
9033
9280
  };
9034
9281
  return /* @__PURE__ */ jsxs28(Fragment13, { children: [
9035
- /* @__PURE__ */ jsx46(View33, { style: styles33.container, children: recyclingInfos.map((recyclingInfo) => {
9282
+ /* @__PURE__ */ jsx47(View33, { style: styles33.container, children: recyclingInfos.map((recyclingInfo) => {
9036
9283
  const color = recyclingInfo.color ?? theme.colors.primary;
9037
9284
  const illustration = resolveApiAssetUrl(apiUrl, recyclingInfo.imageUrl) || (recyclingInfo.icon?.trim().startsWith("http") ? recyclingInfo.icon.trim() : null);
9038
9285
  return /* @__PURE__ */ jsxs28(
@@ -9051,7 +9298,7 @@ function RecyclingInfo({}) {
9051
9298
  { backgroundColor: color }
9052
9299
  ],
9053
9300
  children: [
9054
- illustration ? /* @__PURE__ */ jsx46(
9301
+ illustration ? /* @__PURE__ */ jsx47(
9055
9302
  Image12,
9056
9303
  {
9057
9304
  source: illustration,
@@ -9059,7 +9306,7 @@ function RecyclingInfo({}) {
9059
9306
  contentFit: "contain"
9060
9307
  }
9061
9308
  ) : null,
9062
- /* @__PURE__ */ jsx46(
9309
+ /* @__PURE__ */ jsx47(
9063
9310
  Title,
9064
9311
  {
9065
9312
  text: recyclingInfo.name,
@@ -9071,8 +9318,8 @@ function RecyclingInfo({}) {
9071
9318
  }
9072
9319
  ),
9073
9320
  /* @__PURE__ */ jsxs28(View33, { style: styles33.body, children: [
9074
- recyclingInfo.description && /* @__PURE__ */ jsx46(Paragraph, { text: recyclingInfo.description, style: themedStyles.cardText }),
9075
- /* @__PURE__ */ jsx46(
9321
+ recyclingInfo.description && /* @__PURE__ */ jsx47(Paragraph, { text: recyclingInfo.description, style: themedStyles.cardText }),
9322
+ /* @__PURE__ */ jsx47(
9076
9323
  View33,
9077
9324
  {
9078
9325
  style: [
@@ -9098,7 +9345,7 @@ function RecyclingInfo({}) {
9098
9345
  }
9099
9346
  ],
9100
9347
  children: [
9101
- detailImageUrl ? /* @__PURE__ */ jsx46(
9348
+ detailImageUrl ? /* @__PURE__ */ jsx47(
9102
9349
  Image12,
9103
9350
  {
9104
9351
  source: detailImageUrl,
@@ -9107,7 +9354,7 @@ function RecyclingInfo({}) {
9107
9354
  }
9108
9355
  ) : null,
9109
9356
  /* @__PURE__ */ jsxs28(View33, { style: styles33.detailText, children: [
9110
- /* @__PURE__ */ jsx46(
9357
+ /* @__PURE__ */ jsx47(
9111
9358
  Text27,
9112
9359
  {
9113
9360
  style: [
@@ -9117,7 +9364,7 @@ function RecyclingInfo({}) {
9117
9364
  children: detail.material
9118
9365
  }
9119
9366
  ),
9120
- /* @__PURE__ */ jsx46(
9367
+ /* @__PURE__ */ jsx47(
9121
9368
  Text27,
9122
9369
  {
9123
9370
  style: { color: getContrastColor(recyclingInfo.colorLight ?? "#FFFFFF") },
@@ -9132,7 +9379,7 @@ function RecyclingInfo({}) {
9132
9379
  })
9133
9380
  }
9134
9381
  ),
9135
- /* @__PURE__ */ jsx46(
9382
+ /* @__PURE__ */ jsx47(
9136
9383
  Button,
9137
9384
  {
9138
9385
  style: { backgroundColor: color },
@@ -9147,7 +9394,7 @@ function RecyclingInfo({}) {
9147
9394
  recyclingInfo.id
9148
9395
  );
9149
9396
  }) }),
9150
- /* @__PURE__ */ jsx46(
9397
+ /* @__PURE__ */ jsx47(
9151
9398
  ConsignesModal,
9152
9399
  {
9153
9400
  visible: !!selectedWasteTypeId,
@@ -9207,10 +9454,10 @@ var styles33 = StyleSheet34.create({
9207
9454
  });
9208
9455
 
9209
9456
  // src/components/search/Search.tsx
9210
- import { useEffect as useEffect18, useMemo as useMemo23, useState as useState28 } from "react";
9457
+ import { useEffect as useEffect19, useMemo as useMemo23, useState as useState28 } from "react";
9211
9458
  import { Pressable as Pressable15, StyleSheet as StyleSheet35, Text as Text28, TextInput as TextInput3, View as View34 } from "react-native";
9212
9459
  import { ChevronRight as ChevronRight2, Search as SearchIcon } from "lucide-react-native";
9213
- import { Fragment as Fragment14, jsx as jsx47, jsxs as jsxs29 } from "react/jsx-runtime";
9460
+ import { Fragment as Fragment14, jsx as jsx48, jsxs as jsxs29 } from "react/jsx-runtime";
9214
9461
  function matchesQuery(haystack, query) {
9215
9462
  if (!haystack) return false;
9216
9463
  return haystack.toLowerCase().includes(query);
@@ -9227,14 +9474,14 @@ function ResultRow({
9227
9474
  const t = resolveTheme(theme);
9228
9475
  const content = /* @__PURE__ */ jsxs29(Fragment14, { children: [
9229
9476
  /* @__PURE__ */ jsxs29(View34, { style: styles34.rowInner, children: [
9230
- /* @__PURE__ */ jsx47(View34, { style: [styles34.dot, { backgroundColor: accent }] }),
9477
+ /* @__PURE__ */ jsx48(View34, { style: [styles34.dot, { backgroundColor: accent }] }),
9231
9478
  /* @__PURE__ */ jsxs29(View34, { style: styles34.rowText, children: [
9232
- /* @__PURE__ */ jsx47(Text28, { style: [styles34.rowTitle, { color: theme.colors.onSurface }], children: title }),
9233
- meta ? /* @__PURE__ */ jsx47(Text28, { style: [styles34.rowMeta, { color: t.colors.muted }], numberOfLines: 2, children: meta }) : null
9479
+ /* @__PURE__ */ jsx48(Text28, { style: [styles34.rowTitle, { color: theme.colors.onSurface }], children: title }),
9480
+ meta ? /* @__PURE__ */ jsx48(Text28, { style: [styles34.rowMeta, { color: t.colors.muted }], numberOfLines: 2, children: meta }) : null
9234
9481
  ] }),
9235
- onPress ? /* @__PURE__ */ jsx47(ChevronRight2, { size: 18, color: t.colors.muted }) : null
9482
+ onPress ? /* @__PURE__ */ jsx48(ChevronRight2, { size: 18, color: t.colors.muted }) : null
9236
9483
  ] }),
9237
- showDivider ? /* @__PURE__ */ jsx47(
9484
+ showDivider ? /* @__PURE__ */ jsx48(
9238
9485
  View34,
9239
9486
  {
9240
9487
  style: [
@@ -9248,9 +9495,9 @@ function ResultRow({
9248
9495
  ) : null
9249
9496
  ] });
9250
9497
  if (onPress) {
9251
- return /* @__PURE__ */ jsx47(Pressable15, { onPress, style: ({ pressed }) => pressed && styles34.pressed, children: content });
9498
+ return /* @__PURE__ */ jsx48(Pressable15, { onPress, style: ({ pressed }) => pressed && styles34.pressed, children: content });
9252
9499
  }
9253
- return /* @__PURE__ */ jsx47(View34, { children: content });
9500
+ return /* @__PURE__ */ jsx48(View34, { children: content });
9254
9501
  }
9255
9502
  function ResultSection({
9256
9503
  label,
@@ -9259,8 +9506,8 @@ function ResultSection({
9259
9506
  const { theme } = useTheme();
9260
9507
  const t = resolveTheme(theme);
9261
9508
  return /* @__PURE__ */ jsxs29(View34, { style: styles34.section, children: [
9262
- label ? /* @__PURE__ */ jsx47(Text28, { style: [styles34.sectionLabel, { color: t.colors.muted }], children: label }) : null,
9263
- /* @__PURE__ */ jsx47(View34, { style: groupedSectionStyle(theme), children })
9509
+ label ? /* @__PURE__ */ jsx48(Text28, { style: [styles34.sectionLabel, { color: t.colors.muted }], children: label }) : null,
9510
+ /* @__PURE__ */ jsx48(View34, { style: groupedSectionStyle(theme), children })
9264
9511
  ] });
9265
9512
  }
9266
9513
  function Search2({
@@ -9277,7 +9524,7 @@ function Search2({
9277
9524
  const [query, setQuery] = useState28("");
9278
9525
  const [wasteTypeId, setWasteTypeId] = useState28(null);
9279
9526
  const [article, setArticle] = useState28(null);
9280
- useEffect18(() => {
9527
+ useEffect19(() => {
9281
9528
  const handle = setTimeout(() => setQuery(draft.trim().toLowerCase()), 250);
9282
9529
  return () => clearTimeout(handle);
9283
9530
  }, [draft]);
@@ -9316,8 +9563,8 @@ function Search2({
9316
9563
  }
9317
9564
  ],
9318
9565
  children: [
9319
- /* @__PURE__ */ jsx47(SearchIcon, { size: 18, color: t.colors.muted }),
9320
- /* @__PURE__ */ jsx47(
9566
+ /* @__PURE__ */ jsx48(SearchIcon, { size: 18, color: t.colors.muted }),
9567
+ /* @__PURE__ */ jsx48(
9321
9568
  TextInput3,
9322
9569
  {
9323
9570
  value: draft,
@@ -9332,8 +9579,8 @@ function Search2({
9332
9579
  ]
9333
9580
  }
9334
9581
  ),
9335
- empty ? /* @__PURE__ */ jsx47(Text28, { style: [styles34.empty, { color: t.colors.muted }], children: "Aucun r\xE9sultat" }) : null,
9336
- wasteResults.length > 0 ? /* @__PURE__ */ jsx47(ResultSection, { label: searchType === "all" ? "Consignes" : void 0, children: wasteResults.map((info, index) => /* @__PURE__ */ jsx47(
9582
+ empty ? /* @__PURE__ */ jsx48(Text28, { style: [styles34.empty, { color: t.colors.muted }], children: "Aucun r\xE9sultat" }) : null,
9583
+ wasteResults.length > 0 ? /* @__PURE__ */ jsx48(ResultSection, { label: searchType === "all" ? "Consignes" : void 0, children: wasteResults.map((info, index) => /* @__PURE__ */ jsx48(
9337
9584
  ResultRow,
9338
9585
  {
9339
9586
  title: info.name,
@@ -9345,7 +9592,7 @@ function Search2({
9345
9592
  },
9346
9593
  info.id
9347
9594
  )) }) : null,
9348
- locationResults.length > 0 ? /* @__PURE__ */ jsx47(ResultSection, { label: searchType === "all" ? "Points de collecte" : void 0, children: locationResults.map((loc, index) => /* @__PURE__ */ jsx47(
9595
+ locationResults.length > 0 ? /* @__PURE__ */ jsx48(ResultSection, { label: searchType === "all" ? "Points de collecte" : void 0, children: locationResults.map((loc, index) => /* @__PURE__ */ jsx48(
9349
9596
  ResultRow,
9350
9597
  {
9351
9598
  title: loc.name,
@@ -9359,7 +9606,7 @@ function Search2({
9359
9606
  },
9360
9607
  loc.id
9361
9608
  )) }) : null,
9362
- articleResults.length > 0 ? /* @__PURE__ */ jsx47(ResultSection, { label: searchType === "all" ? "Articles" : void 0, children: articleResults.map((post, index) => /* @__PURE__ */ jsx47(
9609
+ articleResults.length > 0 ? /* @__PURE__ */ jsx48(ResultSection, { label: searchType === "all" ? "Articles" : void 0, children: articleResults.map((post, index) => /* @__PURE__ */ jsx48(
9363
9610
  ResultRow,
9364
9611
  {
9365
9612
  title: post.title,
@@ -9370,7 +9617,7 @@ function Search2({
9370
9617
  },
9371
9618
  post.id
9372
9619
  )) }) : null,
9373
- /* @__PURE__ */ jsx47(
9620
+ /* @__PURE__ */ jsx48(
9374
9621
  ConsignesModal,
9375
9622
  {
9376
9623
  visible: !!wasteTypeId,
@@ -9378,7 +9625,7 @@ function Search2({
9378
9625
  onClose: () => setWasteTypeId(null)
9379
9626
  }
9380
9627
  ),
9381
- /* @__PURE__ */ jsx47(
9628
+ /* @__PURE__ */ jsx48(
9382
9629
  ArticleReaderModal,
9383
9630
  {
9384
9631
  visible: !!article,
@@ -9461,7 +9708,7 @@ var styles34 = StyleSheet35.create({
9461
9708
  import {
9462
9709
  useCallback as useCallback14,
9463
9710
  useLayoutEffect,
9464
- useRef as useRef8,
9711
+ useRef as useRef9,
9465
9712
  useState as useState29
9466
9713
  } from "react";
9467
9714
  import { Pressable as Pressable16, StyleSheet as StyleSheet36, View as View35 } from "react-native";
@@ -9476,7 +9723,7 @@ import Animated6, {
9476
9723
  withSpring
9477
9724
  } from "react-native-reanimated";
9478
9725
  import { useSafeAreaInsets as useSafeAreaInsets2 } from "react-native-safe-area-context";
9479
- import { jsx as jsx48, jsxs as jsxs30 } from "react/jsx-runtime";
9726
+ import { jsx as jsx49, jsxs as jsxs30 } from "react/jsx-runtime";
9480
9727
  var PILL_W = 64;
9481
9728
  var PILL_H = 44;
9482
9729
  var ICON_SIZE = 24;
@@ -9549,11 +9796,11 @@ function TabItem({
9549
9796
  accessibilityLabel: label,
9550
9797
  children: [
9551
9798
  /* @__PURE__ */ jsxs30(View35, { style: styles35.iconSlot, children: [
9552
- /* @__PURE__ */ jsx48(Animated6.View, { style: [styles35.iconLayer, idleIconStyle], children: icon(muted) }),
9553
- /* @__PURE__ */ jsx48(Animated6.View, { style: [styles35.iconLayer, activeIconStyle], children: icon(onPrimary) })
9799
+ /* @__PURE__ */ jsx49(Animated6.View, { style: [styles35.iconLayer, idleIconStyle], children: icon(muted) }),
9800
+ /* @__PURE__ */ jsx49(Animated6.View, { style: [styles35.iconLayer, activeIconStyle], children: icon(onPrimary) })
9554
9801
  ] }),
9555
9802
  /* @__PURE__ */ jsxs30(View35, { style: styles35.labelSlot, children: [
9556
- /* @__PURE__ */ jsx48(
9803
+ /* @__PURE__ */ jsx49(
9557
9804
  Animated6.Text,
9558
9805
  {
9559
9806
  style: [styles35.label, styles35.labelIdle, { color: muted }, idleLabelStyle],
@@ -9561,7 +9808,7 @@ function TabItem({
9561
9808
  children: label
9562
9809
  }
9563
9810
  ),
9564
- /* @__PURE__ */ jsx48(
9811
+ /* @__PURE__ */ jsx49(
9565
9812
  Animated6.Text,
9566
9813
  {
9567
9814
  style: [styles35.label, styles35.labelActive, { color: primary }, activeLabelStyle],
@@ -9594,9 +9841,9 @@ function BottomTab({
9594
9841
  const dragStartIndex = useSharedValue4(state.index);
9595
9842
  const pressed = useSharedValue4(0);
9596
9843
  const lastTick = useSharedValue4(state.index);
9597
- const dragging = useRef8(false);
9598
- const routesRef = useRef8(state.routes);
9599
- const indexRef = useRef8(state.index);
9844
+ const dragging = useRef9(false);
9845
+ const routesRef = useRef9(state.routes);
9846
+ const indexRef = useRef9(state.index);
9600
9847
  routesRef.current = state.routes;
9601
9848
  indexRef.current = state.index;
9602
9849
  countSV.value = count;
@@ -9671,7 +9918,7 @@ function BottomTab({
9671
9918
  left: pillX.value,
9672
9919
  transform: [{ scale: interpolate4(pressed.value, [0, 1], [1, 0.96]) }]
9673
9920
  }), []);
9674
- return /* @__PURE__ */ jsx48(GestureHandlerRootView, { style: styles35.gestureRoot, children: /* @__PURE__ */ jsx48(
9921
+ return /* @__PURE__ */ jsx49(GestureHandlerRootView, { style: styles35.gestureRoot, children: /* @__PURE__ */ jsx49(
9675
9922
  View35,
9676
9923
  {
9677
9924
  style: [
@@ -9679,14 +9926,14 @@ function BottomTab({
9679
9926
  themedStyles.bottomTab,
9680
9927
  { paddingBottom: Math.max(insets.bottom, 12) }
9681
9928
  ],
9682
- children: /* @__PURE__ */ jsx48(GestureDetector2, { gesture: pan, children: /* @__PURE__ */ jsxs30(
9929
+ children: /* @__PURE__ */ jsx49(GestureDetector2, { gesture: pan, children: /* @__PURE__ */ jsxs30(
9683
9930
  View35,
9684
9931
  {
9685
9932
  collapsable: false,
9686
9933
  style: styles35.row,
9687
9934
  onLayout: (e) => setRowWidth(e.nativeEvent.layout.width),
9688
9935
  children: [
9689
- /* @__PURE__ */ jsx48(
9936
+ /* @__PURE__ */ jsx49(
9690
9937
  Animated6.View,
9691
9938
  {
9692
9939
  pointerEvents: "none",
@@ -9703,7 +9950,7 @@ function BottomTab({
9703
9950
  state.routes.map((route, index) => {
9704
9951
  const { options } = descriptors[route.key];
9705
9952
  const label = typeof options.title === "string" ? options.title : route.name;
9706
- return /* @__PURE__ */ jsx48(
9953
+ return /* @__PURE__ */ jsx49(
9707
9954
  TabItem,
9708
9955
  {
9709
9956
  index,
@@ -9807,7 +10054,7 @@ import {
9807
10054
  } from "react-native";
9808
10055
 
9809
10056
  // src/hooks/useCityAnnouncements.ts
9810
- import { useCallback as useCallback15, useEffect as useEffect19, useState as useState30 } from "react";
10057
+ import { useCallback as useCallback15, useEffect as useEffect20, useState as useState30 } from "react";
9811
10058
  import AsyncStorage4 from "@react-native-async-storage/async-storage";
9812
10059
  var DISMISSED_KEY2 = "dismissed_announcements";
9813
10060
  var PAGE_SIZE2 = 20;
@@ -9869,7 +10116,7 @@ function useCityAnnouncements() {
9869
10116
  setLoading(false);
9870
10117
  }
9871
10118
  }, [apiUrl, client.public.announcements, hasPlaceSelected, selectedCityId]);
9872
- useEffect19(() => {
10119
+ useEffect20(() => {
9873
10120
  void reload();
9874
10121
  }, [reload]);
9875
10122
  const items = all.slice(0, visibleCount);
@@ -9904,7 +10151,7 @@ function useCityAnnouncements() {
9904
10151
  }
9905
10152
 
9906
10153
  // src/components/notifications/NotificationsScreen.tsx
9907
- import { jsx as jsx49, jsxs as jsxs31 } from "react/jsx-runtime";
10154
+ import { jsx as jsx50, jsxs as jsxs31 } from "react/jsx-runtime";
9908
10155
  function formatSentAt(value) {
9909
10156
  if (!value) return null;
9910
10157
  const d = new Date(value);
@@ -9950,7 +10197,7 @@ function NotificationsScreen() {
9950
10197
  accessibilityLabel: item.title,
9951
10198
  children: [
9952
10199
  /* @__PURE__ */ jsxs31(View36, { style: styles36.rowHeader, children: [
9953
- /* @__PURE__ */ jsx49(
10200
+ /* @__PURE__ */ jsx50(
9954
10201
  Text29,
9955
10202
  {
9956
10203
  style: [styles36.rowTitle, { color: theme.colors.onSurface }],
@@ -9958,7 +10205,7 @@ function NotificationsScreen() {
9958
10205
  children: item.title
9959
10206
  }
9960
10207
  ),
9961
- item.unread ? /* @__PURE__ */ jsx49(
10208
+ item.unread ? /* @__PURE__ */ jsx50(
9962
10209
  View36,
9963
10210
  {
9964
10211
  style: [
@@ -9968,8 +10215,8 @@ function NotificationsScreen() {
9968
10215
  }
9969
10216
  ) : null
9970
10217
  ] }),
9971
- dateLabel ? /* @__PURE__ */ jsx49(Text29, { style: [styles36.rowMeta, { color: t.colors.muted }], children: dateLabel }) : null,
9972
- /* @__PURE__ */ jsx49(
10218
+ dateLabel ? /* @__PURE__ */ jsx50(Text29, { style: [styles36.rowMeta, { color: t.colors.muted }], children: dateLabel }) : null,
10219
+ /* @__PURE__ */ jsx50(
9973
10220
  Text29,
9974
10221
  {
9975
10222
  style: [styles36.rowBody, { color: t.colors.muted }],
@@ -9985,20 +10232,20 @@ function NotificationsScreen() {
9985
10232
  );
9986
10233
  if (!hasPlaceSelected) {
9987
10234
  return /* @__PURE__ */ jsxs31(View36, { style: styles36.center, children: [
9988
- /* @__PURE__ */ jsx49(Text29, { style: [styles36.emptyTitle, { color: theme.colors.onSurface }], children: "Aucun secteur s\xE9lectionn\xE9" }),
9989
- /* @__PURE__ */ jsx49(Text29, { style: [styles36.emptyText, { color: t.colors.muted }], children: "Choisissez votre rue pour voir les notifications de votre ville." })
10235
+ /* @__PURE__ */ jsx50(Text29, { style: [styles36.emptyTitle, { color: theme.colors.onSurface }], children: "Aucun secteur s\xE9lectionn\xE9" }),
10236
+ /* @__PURE__ */ jsx50(Text29, { style: [styles36.emptyText, { color: t.colors.muted }], children: "Choisissez votre rue pour voir les notifications de votre ville." })
9990
10237
  ] });
9991
10238
  }
9992
10239
  if (loading && items.length === 0) {
9993
- return /* @__PURE__ */ jsx49(View36, { style: styles36.center, children: /* @__PURE__ */ jsx49(ActivityIndicator12, { color: theme.colors.primary }) });
10240
+ return /* @__PURE__ */ jsx50(View36, { style: styles36.center, children: /* @__PURE__ */ jsx50(ActivityIndicator12, { color: theme.colors.primary }) });
9994
10241
  }
9995
10242
  if (error && items.length === 0) {
9996
10243
  return /* @__PURE__ */ jsxs31(View36, { style: styles36.center, children: [
9997
- /* @__PURE__ */ jsx49(Text29, { style: [styles36.emptyTitle, { color: theme.colors.error }], children: error }),
9998
- /* @__PURE__ */ jsx49(Button, { variant: "secondary", onPress: () => void reload(), style: styles36.retry, children: "R\xE9essayer" })
10244
+ /* @__PURE__ */ jsx50(Text29, { style: [styles36.emptyTitle, { color: theme.colors.error }], children: error }),
10245
+ /* @__PURE__ */ jsx50(Button, { variant: "secondary", onPress: () => void reload(), style: styles36.retry, children: "R\xE9essayer" })
9999
10246
  ] });
10000
10247
  }
10001
- return /* @__PURE__ */ jsx49(View36, { style: styles36.screen, children: /* @__PURE__ */ jsx49(
10248
+ return /* @__PURE__ */ jsx50(View36, { style: styles36.screen, children: /* @__PURE__ */ jsx50(
10002
10249
  FlatList3,
10003
10250
  {
10004
10251
  data: items,
@@ -10010,10 +10257,10 @@ function NotificationsScreen() {
10010
10257
  },
10011
10258
  onEndReachedThreshold: 0.4,
10012
10259
  ListEmptyComponent: /* @__PURE__ */ jsxs31(View36, { style: styles36.centerInline, children: [
10013
- /* @__PURE__ */ jsx49(Text29, { style: [styles36.emptyTitle, { color: theme.colors.onSurface }], children: "Aucune notification" }),
10014
- /* @__PURE__ */ jsx49(Text29, { style: [styles36.emptyText, { color: t.colors.muted }], children: "Les annonces de votre ville appara\xEEtront ici." })
10260
+ /* @__PURE__ */ jsx50(Text29, { style: [styles36.emptyTitle, { color: theme.colors.onSurface }], children: "Aucune notification" }),
10261
+ /* @__PURE__ */ jsx50(Text29, { style: [styles36.emptyText, { color: t.colors.muted }], children: "Les annonces de votre ville appara\xEEtront ici." })
10015
10262
  ] }),
10016
- ListFooterComponent: hasMore ? /* @__PURE__ */ jsx49(
10263
+ ListFooterComponent: hasMore ? /* @__PURE__ */ jsx50(
10017
10264
  Button,
10018
10265
  {
10019
10266
  variant: "ghost",
@@ -10107,7 +10354,7 @@ var styles36 = StyleSheet37.create({
10107
10354
  // src/components/profile/ProfileScreen.tsx
10108
10355
  import { Alert, StyleSheet as StyleSheet38, Text as Text30, View as View37 } from "react-native";
10109
10356
  import { MapPin as MapPin5, Trash2 } from "lucide-react-native";
10110
- import { jsx as jsx50, jsxs as jsxs32 } from "react/jsx-runtime";
10357
+ import { jsx as jsx51, jsxs as jsxs32 } from "react/jsx-runtime";
10111
10358
  function RecapRow({
10112
10359
  label,
10113
10360
  value,
@@ -10115,8 +10362,8 @@ function RecapRow({
10115
10362
  onSurface
10116
10363
  }) {
10117
10364
  return /* @__PURE__ */ jsxs32(View37, { style: styles37.recapRow, children: [
10118
- /* @__PURE__ */ jsx50(Text30, { style: [styles37.recapLabel, { color: muted }], children: label }),
10119
- /* @__PURE__ */ jsx50(Text30, { style: [styles37.recapValue, { color: onSurface }], numberOfLines: 2, children: value })
10365
+ /* @__PURE__ */ jsx51(Text30, { style: [styles37.recapLabel, { color: muted }], children: label }),
10366
+ /* @__PURE__ */ jsx51(Text30, { style: [styles37.recapValue, { color: onSurface }], numberOfLines: 2, children: value })
10120
10367
  ] });
10121
10368
  }
10122
10369
  function ProfileScreen() {
@@ -10157,7 +10404,7 @@ function ProfileScreen() {
10157
10404
  };
10158
10405
  return /* @__PURE__ */ jsxs32(View37, { style: styles37.screen, children: [
10159
10406
  /* @__PURE__ */ jsxs32(View37, { style: styles37.section, children: [
10160
- /* @__PURE__ */ jsx50(Text30, { style: [styles37.sectionLabel, { color: t.colors.muted }], children: "MON SECTEUR" }),
10407
+ /* @__PURE__ */ jsx51(Text30, { style: [styles37.sectionLabel, { color: t.colors.muted }], children: "MON SECTEUR" }),
10161
10408
  /* @__PURE__ */ jsxs32(
10162
10409
  View37,
10163
10410
  {
@@ -10168,7 +10415,7 @@ function ProfileScreen() {
10168
10415
  ],
10169
10416
  children: [
10170
10417
  /* @__PURE__ */ jsxs32(View37, { style: styles37.recapHead, children: [
10171
- /* @__PURE__ */ jsx50(
10418
+ /* @__PURE__ */ jsx51(
10172
10419
  View37,
10173
10420
  {
10174
10421
  style: [
@@ -10178,10 +10425,10 @@ function ProfileScreen() {
10178
10425
  borderRadius: t.radii.pill
10179
10426
  }
10180
10427
  ],
10181
- children: /* @__PURE__ */ jsx50(MapPin5, { size: 18, color: theme.colors.onPrimary })
10428
+ children: /* @__PURE__ */ jsx51(MapPin5, { size: 18, color: theme.colors.onPrimary })
10182
10429
  }
10183
10430
  ),
10184
- /* @__PURE__ */ jsx50(
10431
+ /* @__PURE__ */ jsx51(
10185
10432
  Text30,
10186
10433
  {
10187
10434
  style: [styles37.recapTitle, { color: theme.colors.onSurface }],
@@ -10190,7 +10437,7 @@ function ProfileScreen() {
10190
10437
  )
10191
10438
  ] }),
10192
10439
  hasPlaceSelected ? /* @__PURE__ */ jsxs32(View37, { style: styles37.recapList, children: [
10193
- /* @__PURE__ */ jsx50(
10440
+ /* @__PURE__ */ jsx51(
10194
10441
  RecapRow,
10195
10442
  {
10196
10443
  label: "Ville",
@@ -10199,7 +10446,7 @@ function ProfileScreen() {
10199
10446
  onSurface: theme.colors.onSurface
10200
10447
  }
10201
10448
  ),
10202
- /* @__PURE__ */ jsx50(
10449
+ /* @__PURE__ */ jsx51(
10203
10450
  View37,
10204
10451
  {
10205
10452
  style: [
@@ -10208,7 +10455,7 @@ function ProfileScreen() {
10208
10455
  ]
10209
10456
  }
10210
10457
  ),
10211
- /* @__PURE__ */ jsx50(
10458
+ /* @__PURE__ */ jsx51(
10212
10459
  RecapRow,
10213
10460
  {
10214
10461
  label: "Adresse",
@@ -10217,7 +10464,7 @@ function ProfileScreen() {
10217
10464
  onSurface: theme.colors.onSurface
10218
10465
  }
10219
10466
  ),
10220
- /* @__PURE__ */ jsx50(
10467
+ /* @__PURE__ */ jsx51(
10221
10468
  View37,
10222
10469
  {
10223
10470
  style: [
@@ -10226,7 +10473,7 @@ function ProfileScreen() {
10226
10473
  ]
10227
10474
  }
10228
10475
  ),
10229
- /* @__PURE__ */ jsx50(
10476
+ /* @__PURE__ */ jsx51(
10230
10477
  RecapRow,
10231
10478
  {
10232
10479
  label: "Secteur",
@@ -10235,15 +10482,15 @@ function ProfileScreen() {
10235
10482
  onSurface: theme.colors.onSurface
10236
10483
  }
10237
10484
  )
10238
- ] }) : /* @__PURE__ */ jsx50(Text30, { style: [styles37.emptyHint, { color: t.colors.muted }], children: "Choisissez votre rue pour personnaliser les collectes et notifications." })
10485
+ ] }) : /* @__PURE__ */ jsx51(Text30, { style: [styles37.emptyHint, { color: t.colors.muted }], children: "Choisissez votre rue pour personnaliser les collectes et notifications." })
10239
10486
  ]
10240
10487
  }
10241
10488
  )
10242
10489
  ] }),
10243
10490
  /* @__PURE__ */ jsxs32(View37, { style: styles37.section, children: [
10244
- /* @__PURE__ */ jsx50(Text30, { style: [styles37.sectionLabel, { color: t.colors.muted }], children: "ACTIONS" }),
10491
+ /* @__PURE__ */ jsx51(Text30, { style: [styles37.sectionLabel, { color: t.colors.muted }], children: "ACTIONS" }),
10245
10492
  /* @__PURE__ */ jsxs32(View37, { style: styles37.actions, children: [
10246
- /* @__PURE__ */ jsx50(
10493
+ /* @__PURE__ */ jsx51(
10247
10494
  Button,
10248
10495
  {
10249
10496
  variant: "secondary",
@@ -10253,7 +10500,7 @@ function ProfileScreen() {
10253
10500
  children: "Changer de secteur"
10254
10501
  }
10255
10502
  ),
10256
- /* @__PURE__ */ jsx50(
10503
+ /* @__PURE__ */ jsx51(
10257
10504
  Button,
10258
10505
  {
10259
10506
  variant: "ghost",
@@ -10336,7 +10583,7 @@ import { useCallback as useCallback18, useState as useState32 } from "react";
10336
10583
  import {
10337
10584
  ActivityIndicator as ActivityIndicator13,
10338
10585
  Modal as Modal11,
10339
- Platform as Platform6,
10586
+ Platform as Platform8,
10340
10587
  StyleSheet as StyleSheet42,
10341
10588
  Text as Text34,
10342
10589
  View as View41
@@ -10344,13 +10591,13 @@ import {
10344
10591
 
10345
10592
  // src/components/vision/VisionCapture.tsx
10346
10593
  import { StyleSheet as StyleSheet39, Text as Text31, View as View38 } from "react-native";
10347
- import { jsx as jsx51, jsxs as jsxs33 } from "react/jsx-runtime";
10594
+ import { jsx as jsx52, jsxs as jsxs33 } from "react/jsx-runtime";
10348
10595
  function VisionCapture({ tips, onCapture, busy }) {
10349
10596
  const { theme } = useTheme();
10350
10597
  const t = resolveTheme(theme);
10351
10598
  return /* @__PURE__ */ jsxs33(View38, { style: styles38.root, children: [
10352
- /* @__PURE__ */ jsx51(Text31, { style: [styles38.tips, { color: t.colors.muted }], children: tips }),
10353
- /* @__PURE__ */ jsx51(Button, { onPress: onCapture, disabled: busy, loading: busy, children: busy ? "Ouverture\u2026" : "Prendre une photo" })
10599
+ /* @__PURE__ */ jsx52(Text31, { style: [styles38.tips, { color: t.colors.muted }], children: tips }),
10600
+ /* @__PURE__ */ jsx52(Button, { onPress: onCapture, disabled: busy, loading: busy, children: busy ? "Ouverture\u2026" : "Prendre une photo" })
10354
10601
  ] });
10355
10602
  }
10356
10603
  var styles38 = StyleSheet39.create({
@@ -10367,7 +10614,7 @@ import {
10367
10614
  View as View39
10368
10615
  } from "react-native";
10369
10616
  import { Image as Image13 } from "expo-image";
10370
- import { jsx as jsx52, jsxs as jsxs34 } from "react/jsx-runtime";
10617
+ import { jsx as jsx53, jsxs as jsxs34 } from "react/jsx-runtime";
10371
10618
  function VisionTapOverlay({
10372
10619
  imageUri,
10373
10620
  tap,
@@ -10385,7 +10632,7 @@ function VisionTapOverlay({
10385
10632
  setSize({ w: Math.max(width, 1), h: Math.max(height, 1) });
10386
10633
  }, []);
10387
10634
  return /* @__PURE__ */ jsxs34(View39, { style: styles39.root, children: [
10388
- /* @__PURE__ */ jsx52(Text32, { style: [styles39.hint, { color: t.colors.muted }], children: "Touchez le d\xE9chet sur la photo, ou analysez toute l\u2019image." }),
10635
+ /* @__PURE__ */ jsx53(Text32, { style: [styles39.hint, { color: t.colors.muted }], children: "Touchez le d\xE9chet sur la photo, ou analysez toute l\u2019image." }),
10389
10636
  /* @__PURE__ */ jsxs34(
10390
10637
  Pressable18,
10391
10638
  {
@@ -10402,8 +10649,8 @@ function VisionTapOverlay({
10402
10649
  { borderRadius: t.radii.md, backgroundColor: t.colors.onSurface }
10403
10650
  ],
10404
10651
  children: [
10405
- /* @__PURE__ */ jsx52(Image13, { source: { uri: imageUri }, style: styles39.image, contentFit: "contain" }),
10406
- tap ? /* @__PURE__ */ jsx52(
10652
+ /* @__PURE__ */ jsx53(Image13, { source: { uri: imageUri }, style: styles39.image, contentFit: "contain" }),
10653
+ tap ? /* @__PURE__ */ jsx53(
10407
10654
  View39,
10408
10655
  {
10409
10656
  pointerEvents: "none",
@@ -10421,8 +10668,8 @@ function VisionTapOverlay({
10421
10668
  }
10422
10669
  ),
10423
10670
  /* @__PURE__ */ jsxs34(View39, { style: styles39.row, children: [
10424
- /* @__PURE__ */ jsx52(Button, { variant: "outline", onPress: onRetake, disabled: busy, style: styles39.flexBtn, children: "Reprendre" }),
10425
- /* @__PURE__ */ jsx52(
10671
+ /* @__PURE__ */ jsx53(Button, { variant: "outline", onPress: onRetake, disabled: busy, style: styles39.flexBtn, children: "Reprendre" }),
10672
+ /* @__PURE__ */ jsx53(
10426
10673
  Button,
10427
10674
  {
10428
10675
  variant: "secondary",
@@ -10432,7 +10679,7 @@ function VisionTapOverlay({
10432
10679
  children: "Toute l\u2019image"
10433
10680
  }
10434
10681
  ),
10435
- /* @__PURE__ */ jsx52(
10682
+ /* @__PURE__ */ jsx53(
10436
10683
  Button,
10437
10684
  {
10438
10685
  onPress: onConfirmTap,
@@ -10468,7 +10715,7 @@ var styles39 = StyleSheet40.create({
10468
10715
 
10469
10716
  // src/components/vision/VisionActionCard.tsx
10470
10717
  import { StyleSheet as StyleSheet41, Text as Text33, View as View40 } from "react-native";
10471
- import { jsx as jsx53, jsxs as jsxs35 } from "react/jsx-runtime";
10718
+ import { jsx as jsx54, jsxs as jsxs35 } from "react/jsx-runtime";
10472
10719
  function VisionActionCard({
10473
10720
  suggestions,
10474
10721
  primaryLabel,
@@ -10502,18 +10749,18 @@ function VisionActionCard({
10502
10749
  }
10503
10750
  ],
10504
10751
  children: [
10505
- /* @__PURE__ */ jsx53(Text33, { style: [styles40.title, { color: t.colors.onSurface }], children: primary.title }),
10506
- /* @__PURE__ */ jsx53(Text33, { style: [styles40.body, { color: t.colors.muted }], children: primary.body })
10752
+ /* @__PURE__ */ jsx54(Text33, { style: [styles40.title, { color: t.colors.onSurface }], children: primary.title }),
10753
+ /* @__PURE__ */ jsx54(Text33, { style: [styles40.body, { color: t.colors.muted }], children: primary.body })
10507
10754
  ]
10508
10755
  }
10509
10756
  ) : null,
10510
10757
  pedagogy ? /* @__PURE__ */ jsxs35(View40, { style: styles40.pedagogy, children: [
10511
- /* @__PURE__ */ jsx53(Text33, { style: [styles40.title, { color: t.colors.onSurface }], children: pedagogy.title }),
10512
- /* @__PURE__ */ jsx53(Text33, { style: [styles40.body, { color: t.colors.muted }], children: pedagogy.body })
10758
+ /* @__PURE__ */ jsx54(Text33, { style: [styles40.title, { color: t.colors.onSurface }], children: pedagogy.title }),
10759
+ /* @__PURE__ */ jsx54(Text33, { style: [styles40.body, { color: t.colors.muted }], children: pedagogy.body })
10513
10760
  ] }) : null,
10514
10761
  /* @__PURE__ */ jsxs35(View40, { style: styles40.row, children: [
10515
- /* @__PURE__ */ jsx53(Button, { variant: "outline", onPress: onRetake, disabled: busy, style: styles40.flexBtn, children: "Reprendre" }),
10516
- /* @__PURE__ */ jsx53(
10762
+ /* @__PURE__ */ jsx54(Button, { variant: "outline", onPress: onRetake, disabled: busy, style: styles40.flexBtn, children: "Reprendre" }),
10763
+ /* @__PURE__ */ jsx54(
10517
10764
  Button,
10518
10765
  {
10519
10766
  variant: "outline",
@@ -10524,7 +10771,7 @@ function VisionActionCard({
10524
10771
  children: "Ce n\u2019est pas \xE7a"
10525
10772
  }
10526
10773
  ),
10527
- !isUnsure && requireConfirm ? /* @__PURE__ */ jsx53(
10774
+ !isUnsure && requireConfirm ? /* @__PURE__ */ jsx54(
10528
10775
  Button,
10529
10776
  {
10530
10777
  onPress: onConfirm,
@@ -10549,7 +10796,7 @@ var styles40 = StyleSheet41.create({
10549
10796
  });
10550
10797
 
10551
10798
  // src/components/vision/Vision.tsx
10552
- import { jsx as jsx54, jsxs as jsxs36 } from "react/jsx-runtime";
10799
+ import { jsx as jsx55, jsxs as jsxs36 } from "react/jsx-runtime";
10553
10800
  var DEFAULT_TITLE = "Wast\u2019O Scan";
10554
10801
  var DEFAULT_DESCRIPTION = "Photographiez un d\xE9chet, touchez-le sur la photo, puis suivez la consigne locale.";
10555
10802
  var TIPS = "Astuce : bonne lumi\xE8re, objet centr\xE9, un d\xE9chet \xE0 la fois si possible.";
@@ -10774,25 +11021,25 @@ function Vision({
10774
11021
  { minHeight: cardMinHeight }
10775
11022
  ],
10776
11023
  children: [
10777
- /* @__PURE__ */ jsx54(Text34, { style: [styles41.cardTitle, { color: t.colors.onSurface }], children: displayTitle }),
10778
- /* @__PURE__ */ jsx54(Text34, { style: [styles41.cardDescription, { color: t.colors.muted }], children: displayDescription }),
10779
- errorMessage && !modalVisible ? /* @__PURE__ */ jsx54(Text34, { style: [styles41.errorInline, { color: t.colors.error }], children: errorMessage }) : null,
10780
- /* @__PURE__ */ jsx54(Button, { onPress: openScan, children: "Scanner un d\xE9chet" }),
10781
- /* @__PURE__ */ jsx54(
11024
+ /* @__PURE__ */ jsx55(Text34, { style: [styles41.cardTitle, { color: t.colors.onSurface }], children: displayTitle }),
11025
+ /* @__PURE__ */ jsx55(Text34, { style: [styles41.cardDescription, { color: t.colors.muted }], children: displayDescription }),
11026
+ errorMessage && !modalVisible ? /* @__PURE__ */ jsx55(Text34, { style: [styles41.errorInline, { color: t.colors.error }], children: errorMessage }) : null,
11027
+ /* @__PURE__ */ jsx55(Button, { onPress: openScan, children: "Scanner un d\xE9chet" }),
11028
+ /* @__PURE__ */ jsx55(
10782
11029
  Modal11,
10783
11030
  {
10784
11031
  visible: modalVisible,
10785
11032
  animationType: "fade",
10786
- presentationStyle: Platform6.OS === "ios" ? "fullScreen" : void 0,
11033
+ presentationStyle: Platform8.OS === "ios" ? "fullScreen" : void 0,
10787
11034
  statusBarTranslucent: true,
10788
11035
  onRequestClose: closeModal,
10789
11036
  children: /* @__PURE__ */ jsxs36(View41, { style: [styles41.modalRoot, { backgroundColor: t.colors.background }], children: [
10790
11037
  /* @__PURE__ */ jsxs36(View41, { style: styles41.modalHeader, children: [
10791
- /* @__PURE__ */ jsx54(Text34, { style: [styles41.modalTitle, { color: t.colors.onSurface }], children: displayTitle }),
10792
- /* @__PURE__ */ jsx54(Button, { variant: "ghost", onPress: closeModal, children: "Fermer" })
11038
+ /* @__PURE__ */ jsx55(Text34, { style: [styles41.modalTitle, { color: t.colors.onSurface }], children: displayTitle }),
11039
+ /* @__PURE__ */ jsx55(Button, { variant: "ghost", onPress: closeModal, children: "Fermer" })
10793
11040
  ] }),
10794
11041
  /* @__PURE__ */ jsxs36(View41, { style: styles41.modalBody, children: [
10795
- phase === "capture" ? /* @__PURE__ */ jsx54(
11042
+ phase === "capture" ? /* @__PURE__ */ jsx55(
10796
11043
  VisionCapture,
10797
11044
  {
10798
11045
  tips: TIPS,
@@ -10800,7 +11047,7 @@ function Vision({
10800
11047
  busy
10801
11048
  }
10802
11049
  ) : null,
10803
- phase === "tap" && imageUri ? /* @__PURE__ */ jsx54(
11050
+ phase === "tap" && imageUri ? /* @__PURE__ */ jsx55(
10804
11051
  VisionTapOverlay,
10805
11052
  {
10806
11053
  imageUri,
@@ -10813,10 +11060,10 @@ function Vision({
10813
11060
  }
10814
11061
  ) : null,
10815
11062
  phase === "loading" ? /* @__PURE__ */ jsxs36(View41, { style: styles41.center, children: [
10816
- /* @__PURE__ */ jsx54(ActivityIndicator13, { size: "large", color: t.colors.primary }),
10817
- /* @__PURE__ */ jsx54(Text34, { style: { color: t.colors.muted, marginTop: 12 }, children: "Analyse en cours\u2026" })
11063
+ /* @__PURE__ */ jsx55(ActivityIndicator13, { size: "large", color: t.colors.primary }),
11064
+ /* @__PURE__ */ jsx55(Text34, { style: { color: t.colors.muted, marginTop: 12 }, children: "Analyse en cours\u2026" })
10818
11065
  ] }) : null,
10819
- phase === "card" ? /* @__PURE__ */ jsx54(
11066
+ phase === "card" ? /* @__PURE__ */ jsx55(
10820
11067
  VisionActionCard,
10821
11068
  {
10822
11069
  suggestions,
@@ -10830,9 +11077,9 @@ function Vision({
10830
11077
  }
10831
11078
  ) : null,
10832
11079
  phase === "error" ? /* @__PURE__ */ jsxs36(View41, { style: styles41.center, children: [
10833
- /* @__PURE__ */ jsx54(Text34, { style: { color: t.colors.error, fontWeight: "700" }, children: "Impossible d\u2019analyser" }),
10834
- /* @__PURE__ */ jsx54(Text34, { style: { color: t.colors.muted, marginTop: 8 }, children: errorMessage }),
10835
- /* @__PURE__ */ jsx54(Button, { onPress: resetFlow, style: styles41.retry, children: "R\xE9essayer" })
11080
+ /* @__PURE__ */ jsx55(Text34, { style: { color: t.colors.error, fontWeight: "700" }, children: "Impossible d\u2019analyser" }),
11081
+ /* @__PURE__ */ jsx55(Text34, { style: { color: t.colors.muted, marginTop: 8 }, children: errorMessage }),
11082
+ /* @__PURE__ */ jsx55(Button, { onPress: resetFlow, style: styles41.retry, children: "R\xE9essayer" })
10836
11083
  ] }) : null
10837
11084
  ] })
10838
11085
  ] })
@@ -10850,7 +11097,7 @@ var styles41 = StyleSheet42.create({
10850
11097
  cardTitle: { fontSize: 18, fontWeight: "700" },
10851
11098
  cardDescription: { fontSize: 14, lineHeight: 20 },
10852
11099
  errorInline: { fontSize: 13 },
10853
- modalRoot: { flex: 1, paddingTop: Platform6.OS === "ios" ? 56 : 24 },
11100
+ modalRoot: { flex: 1, paddingTop: Platform8.OS === "ios" ? 56 : 24 },
10854
11101
  modalHeader: {
10855
11102
  flexDirection: "row",
10856
11103
  justifyContent: "space-between",
@@ -10939,7 +11186,9 @@ export {
10939
11186
  CollectionCalendar,
10940
11187
  Columns,
10941
11188
  ContentInset,
11189
+ DEFAULT_HEADER_ACTIONS,
10942
11190
  Header,
11191
+ HeaderConfigProvider,
10943
11192
  Image10 as Image,
10944
11193
  LocationsMap,
10945
11194
  MAQUETTE_COLORS,
@@ -10964,11 +11213,13 @@ export {
10964
11213
  groupedSectionStyle,
10965
11214
  initWastoSentry,
10966
11215
  isWastoSentryActive,
11216
+ registerExpoPushToken,
10967
11217
  reportError,
10968
11218
  resolveTheme,
10969
11219
  softCardStyle,
10970
11220
  useAppData,
10971
11221
  useAppNavigation,
11222
+ useHeaderConfig,
10972
11223
  useOptionalAppData,
10973
11224
  useOptionalAppNavigation,
10974
11225
  useWasto,