@cachly-dev/mcp-server 0.10.64 → 0.10.66

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.
Files changed (270) hide show
  1. package/dist/src/handlers/brain.js +1 -1
  2. package/dist/src/index.js +1 -1
  3. package/package.json +7 -1
  4. package/server.json +2 -2
  5. package/.env.test.example +0 -23
  6. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -50
  7. package/.github/ISSUE_TEMPLATE/config.yml +0 -8
  8. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -25
  9. package/.github/workflows/eas-build-android.yml +0 -58
  10. package/.github/workflows/eas-update.yml +0 -55
  11. package/.github/workflows/publish.yml +0 -72
  12. package/BENCH.md +0 -91
  13. package/CHANGELOG.md +0 -604
  14. package/CHANGELOG.md.tmp +0 -0
  15. package/Dockerfile +0 -16
  16. package/LAUNCH_TEXTS.md +0 -182
  17. package/PROGRESS.md +0 -137
  18. package/STRATEGY.md +0 -228
  19. package/VISION_10X.md +0 -133
  20. package/apps/travel-chaos-organizer/.env.example +0 -49
  21. package/apps/travel-chaos-organizer/DEPLOY.md +0 -328
  22. package/apps/travel-chaos-organizer/Makefile +0 -57
  23. package/apps/travel-chaos-organizer/README.md +0 -159
  24. package/apps/travel-chaos-organizer/backend/.env.example +0 -10
  25. package/apps/travel-chaos-organizer/backend/Dockerfile +0 -25
  26. package/apps/travel-chaos-organizer/backend/alembic/env.py +0 -56
  27. package/apps/travel-chaos-organizer/backend/alembic/script.py.mako +0 -24
  28. package/apps/travel-chaos-organizer/backend/alembic/versions/.gitkeep +0 -0
  29. package/apps/travel-chaos-organizer/backend/alembic/versions/0001_stripe_customer_id.py +0 -24
  30. package/apps/travel-chaos-organizer/backend/alembic/versions/0002_telegram_chat_id.py +0 -24
  31. package/apps/travel-chaos-organizer/backend/alembic.ini +0 -39
  32. package/apps/travel-chaos-organizer/backend/app/__init__.py +0 -0
  33. package/apps/travel-chaos-organizer/backend/app/auth/__init__.py +0 -0
  34. package/apps/travel-chaos-organizer/backend/app/auth/keycloak.py +0 -81
  35. package/apps/travel-chaos-organizer/backend/app/config.py +0 -66
  36. package/apps/travel-chaos-organizer/backend/app/db/__init__.py +0 -0
  37. package/apps/travel-chaos-organizer/backend/app/db/database.py +0 -20
  38. package/apps/travel-chaos-organizer/backend/app/db/migrations/001_init.sql +0 -71
  39. package/apps/travel-chaos-organizer/backend/app/db/migrations/002_telemetry_freemium.sql +0 -31
  40. package/apps/travel-chaos-organizer/backend/app/db/migrations/003_telegram_chat_id.sql +0 -4
  41. package/apps/travel-chaos-organizer/backend/app/db/migrations/004_stripe_and_email.sql +0 -5
  42. package/apps/travel-chaos-organizer/backend/app/limiter.py +0 -4
  43. package/apps/travel-chaos-organizer/backend/app/logging_config.py +0 -25
  44. package/apps/travel-chaos-organizer/backend/app/main.py +0 -77
  45. package/apps/travel-chaos-organizer/backend/app/models/__init__.py +0 -0
  46. package/apps/travel-chaos-organizer/backend/app/models/schemas.py +0 -142
  47. package/apps/travel-chaos-organizer/backend/app/routers/__init__.py +0 -0
  48. package/apps/travel-chaos-organizer/backend/app/routers/admin.py +0 -237
  49. package/apps/travel-chaos-organizer/backend/app/routers/cache.py +0 -13
  50. package/apps/travel-chaos-organizer/backend/app/routers/events.py +0 -29
  51. package/apps/travel-chaos-organizer/backend/app/routers/export.py +0 -122
  52. package/apps/travel-chaos-organizer/backend/app/routers/inbox.py +0 -122
  53. package/apps/travel-chaos-organizer/backend/app/routers/items.py +0 -130
  54. package/apps/travel-chaos-organizer/backend/app/routers/mail.py +0 -108
  55. package/apps/travel-chaos-organizer/backend/app/routers/parse.py +0 -303
  56. package/apps/travel-chaos-organizer/backend/app/routers/payments.py +0 -179
  57. package/apps/travel-chaos-organizer/backend/app/routers/trips.py +0 -134
  58. package/apps/travel-chaos-organizer/backend/app/routers/users.py +0 -169
  59. package/apps/travel-chaos-organizer/backend/app/routers/waitlist.py +0 -37
  60. package/apps/travel-chaos-organizer/backend/app/services/__init__.py +0 -0
  61. package/apps/travel-chaos-organizer/backend/app/services/cache.py +0 -131
  62. package/apps/travel-chaos-organizer/backend/app/services/drip.py +0 -128
  63. package/apps/travel-chaos-organizer/backend/app/services/email.py +0 -61
  64. package/apps/travel-chaos-organizer/backend/app/services/errors.py +0 -44
  65. package/apps/travel-chaos-organizer/backend/app/services/notifier.py +0 -10
  66. package/apps/travel-chaos-organizer/backend/app/services/ollama.py +0 -101
  67. package/apps/travel-chaos-organizer/backend/app/services/parser.py +0 -22
  68. package/apps/travel-chaos-organizer/backend/app/services/quota.py +0 -85
  69. package/apps/travel-chaos-organizer/backend/app/services/sentry.py +0 -11
  70. package/apps/travel-chaos-organizer/backend/app/services/telemetry.py +0 -35
  71. package/apps/travel-chaos-organizer/backend/pytest.ini +0 -4
  72. package/apps/travel-chaos-organizer/backend/requirements-dev.txt +0 -6
  73. package/apps/travel-chaos-organizer/backend/requirements.txt +0 -25
  74. package/apps/travel-chaos-organizer/backend/tests/__init__.py +0 -0
  75. package/apps/travel-chaos-organizer/backend/tests/conftest.py +0 -223
  76. package/apps/travel-chaos-organizer/backend/tests/test_admin.py +0 -99
  77. package/apps/travel-chaos-organizer/backend/tests/test_cache.py +0 -142
  78. package/apps/travel-chaos-organizer/backend/tests/test_drip.py +0 -32
  79. package/apps/travel-chaos-organizer/backend/tests/test_e2e_chain.py +0 -121
  80. package/apps/travel-chaos-organizer/backend/tests/test_export.py +0 -48
  81. package/apps/travel-chaos-organizer/backend/tests/test_inbox.py +0 -107
  82. package/apps/travel-chaos-organizer/backend/tests/test_items.py +0 -138
  83. package/apps/travel-chaos-organizer/backend/tests/test_mail.py +0 -113
  84. package/apps/travel-chaos-organizer/backend/tests/test_ollama.py +0 -145
  85. package/apps/travel-chaos-organizer/backend/tests/test_parse_url.py +0 -98
  86. package/apps/travel-chaos-organizer/backend/tests/test_parser.py +0 -72
  87. package/apps/travel-chaos-organizer/backend/tests/test_payments.py +0 -163
  88. package/apps/travel-chaos-organizer/backend/tests/test_quota.py +0 -46
  89. package/apps/travel-chaos-organizer/backend/tests/test_search.py +0 -67
  90. package/apps/travel-chaos-organizer/backend/tests/test_trips.py +0 -123
  91. package/apps/travel-chaos-organizer/backend/tests/test_users.py +0 -52
  92. package/apps/travel-chaos-organizer/backups/.gitkeep +0 -0
  93. package/apps/travel-chaos-organizer/caddy/Caddyfile +0 -27
  94. package/apps/travel-chaos-organizer/docker-compose.node1.yml +0 -31
  95. package/apps/travel-chaos-organizer/docker-compose.override.yml +0 -14
  96. package/apps/travel-chaos-organizer/docker-compose.yml +0 -128
  97. package/apps/travel-chaos-organizer/frontend/.env.example +0 -13
  98. package/apps/travel-chaos-organizer/frontend/app/(app)/_layout.tsx +0 -80
  99. package/apps/travel-chaos-organizer/frontend/app/(app)/inbox.tsx +0 -166
  100. package/apps/travel-chaos-organizer/frontend/app/(app)/search.tsx +0 -130
  101. package/apps/travel-chaos-organizer/frontend/app/(app)/settings.tsx +0 -381
  102. package/apps/travel-chaos-organizer/frontend/app/(app)/trips/[id].tsx +0 -346
  103. package/apps/travel-chaos-organizer/frontend/app/(app)/trips.tsx +0 -363
  104. package/apps/travel-chaos-organizer/frontend/app/(app)/upgrade/cancel.tsx +0 -34
  105. package/apps/travel-chaos-organizer/frontend/app/(app)/upgrade/success.tsx +0 -35
  106. package/apps/travel-chaos-organizer/frontend/app/(auth)/login.tsx +0 -91
  107. package/apps/travel-chaos-organizer/frontend/app/_layout.tsx +0 -71
  108. package/apps/travel-chaos-organizer/frontend/app/auth.tsx +0 -29
  109. package/apps/travel-chaos-organizer/frontend/app/index.tsx +0 -16
  110. package/apps/travel-chaos-organizer/frontend/app/onboarding.tsx +0 -119
  111. package/apps/travel-chaos-organizer/frontend/app.config.ts +0 -54
  112. package/apps/travel-chaos-organizer/frontend/assets/adaptive-icon.svg +0 -66
  113. package/apps/travel-chaos-organizer/frontend/assets/icon.svg +0 -79
  114. package/apps/travel-chaos-organizer/frontend/assets/splash.svg +0 -15
  115. package/apps/travel-chaos-organizer/frontend/components/BottomSheet.tsx +0 -102
  116. package/apps/travel-chaos-organizer/frontend/components/ConfettiCannon.tsx +0 -107
  117. package/apps/travel-chaos-organizer/frontend/components/ConfirmDialog.tsx +0 -109
  118. package/apps/travel-chaos-organizer/frontend/components/ErrorBoundary.tsx +0 -45
  119. package/apps/travel-chaos-organizer/frontend/components/FileUploadButton.tsx +0 -19
  120. package/apps/travel-chaos-organizer/frontend/components/ImportSheet.tsx +0 -155
  121. package/apps/travel-chaos-organizer/frontend/components/OfflineBadge.tsx +0 -55
  122. package/apps/travel-chaos-organizer/frontend/components/QRCodeViewer.tsx +0 -80
  123. package/apps/travel-chaos-organizer/frontend/components/ScoreRing.tsx +0 -39
  124. package/apps/travel-chaos-organizer/frontend/components/Screen.tsx +0 -39
  125. package/apps/travel-chaos-organizer/frontend/components/Skeleton.tsx +0 -70
  126. package/apps/travel-chaos-organizer/frontend/components/SwipeableInboxItem.tsx +0 -121
  127. package/apps/travel-chaos-organizer/frontend/components/SwipeableTimelineItem.tsx +0 -70
  128. package/apps/travel-chaos-organizer/frontend/components/TimelineItem.tsx +0 -73
  129. package/apps/travel-chaos-organizer/frontend/components/TimelineItemDetail.tsx +0 -130
  130. package/apps/travel-chaos-organizer/frontend/components/Toast.tsx +0 -60
  131. package/apps/travel-chaos-organizer/frontend/components/ToastContext.tsx +0 -42
  132. package/apps/travel-chaos-organizer/frontend/components/TripCard.tsx +0 -146
  133. package/apps/travel-chaos-organizer/frontend/components/TripQRModal.tsx +0 -70
  134. package/apps/travel-chaos-organizer/frontend/components/UpgradeBanner.tsx +0 -44
  135. package/apps/travel-chaos-organizer/frontend/eas.json +0 -22
  136. package/apps/travel-chaos-organizer/frontend/hooks/useInbox.ts +0 -24
  137. package/apps/travel-chaos-organizer/frontend/hooks/useNetworkSync.ts +0 -60
  138. package/apps/travel-chaos-organizer/frontend/hooks/useTrips.ts +0 -112
  139. package/apps/travel-chaos-organizer/frontend/lib/api.ts +0 -223
  140. package/apps/travel-chaos-organizer/frontend/lib/auth.ts +0 -93
  141. package/apps/travel-chaos-organizer/frontend/lib/db.ts +0 -86
  142. package/apps/travel-chaos-organizer/frontend/lib/fileCache.ts +0 -54
  143. package/apps/travel-chaos-organizer/frontend/lib/haptics.ts +0 -13
  144. package/apps/travel-chaos-organizer/frontend/lib/notifications.ts +0 -112
  145. package/apps/travel-chaos-organizer/frontend/lib/offlineQueue.ts +0 -145
  146. package/apps/travel-chaos-organizer/frontend/lib/quota.tsx +0 -43
  147. package/apps/travel-chaos-organizer/frontend/lib/sentry.ts +0 -28
  148. package/apps/travel-chaos-organizer/frontend/lib/shareIntent.ts +0 -44
  149. package/apps/travel-chaos-organizer/frontend/package-lock.json +0 -13221
  150. package/apps/travel-chaos-organizer/frontend/package.json +0 -44
  151. package/apps/travel-chaos-organizer/frontend/tsconfig.json +0 -23
  152. package/apps/travel-chaos-organizer/keycloak/realm-export.json +0 -59
  153. package/apps/travel-chaos-organizer/landing/index.html +0 -773
  154. package/apps/travel-chaos-organizer/scripts/backup.sh +0 -14
  155. package/apps/travel-chaos-organizer/scripts/configure-env.sh +0 -82
  156. package/apps/travel-chaos-organizer/scripts/deploy.sh +0 -54
  157. package/apps/travel-chaos-organizer/scripts/health-check.sh +0 -36
  158. package/apps/travel-chaos-organizer/scripts/migrate.sh +0 -7
  159. package/apps/travel-chaos-organizer/scripts/server-setup.sh +0 -85
  160. package/apps/travel-chaos-organizer/scripts/smoke-test.sh +0 -29
  161. package/apps/travel-chaos-organizer/scripts/verify-tracking.sh +0 -71
  162. package/apps/travel-chaos-organizer/telegram-bot/.env.example +0 -3
  163. package/apps/travel-chaos-organizer/telegram-bot/Dockerfile +0 -6
  164. package/apps/travel-chaos-organizer/telegram-bot/bot.py +0 -504
  165. package/apps/travel-chaos-organizer/telegram-bot/requirements.txt +0 -3
  166. package/dist/src/__tests__/auth.test.d.ts +0 -1
  167. package/dist/src/__tests__/auth.test.js +0 -107
  168. package/dist/src/__tests__/auth.test.js.map +0 -1
  169. package/dist/src/__tests__/brain-flow.test.d.ts +0 -12
  170. package/dist/src/__tests__/brain-flow.test.js +0 -1241
  171. package/dist/src/__tests__/brain-flow.test.js.map +0 -1
  172. package/dist/src/__tests__/confidence.test.d.ts +0 -13
  173. package/dist/src/__tests__/confidence.test.js +0 -233
  174. package/dist/src/__tests__/confidence.test.js.map +0 -1
  175. package/dist/src/__tests__/e2e/api-auth.test.d.ts +0 -7
  176. package/dist/src/__tests__/e2e/api-auth.test.js +0 -162
  177. package/dist/src/__tests__/e2e/api-auth.test.js.map +0 -1
  178. package/dist/src/__tests__/e2e/api-health.test.d.ts +0 -7
  179. package/dist/src/__tests__/e2e/api-health.test.js +0 -95
  180. package/dist/src/__tests__/e2e/api-health.test.js.map +0 -1
  181. package/dist/src/__tests__/e2e/cli.test.d.ts +0 -10
  182. package/dist/src/__tests__/e2e/cli.test.js +0 -204
  183. package/dist/src/__tests__/e2e/cli.test.js.map +0 -1
  184. package/dist/src/__tests__/e2e/config.d.ts +0 -35
  185. package/dist/src/__tests__/e2e/config.js +0 -53
  186. package/dist/src/__tests__/e2e/config.js.map +0 -1
  187. package/dist/src/__tests__/e2e/funnel.test.d.ts +0 -13
  188. package/dist/src/__tests__/e2e/funnel.test.js +0 -90
  189. package/dist/src/__tests__/e2e/funnel.test.js.map +0 -1
  190. package/dist/src/__tests__/e2e/mcp-tools.test.d.ts +0 -7
  191. package/dist/src/__tests__/e2e/mcp-tools.test.js +0 -129
  192. package/dist/src/__tests__/e2e/mcp-tools.test.js.map +0 -1
  193. package/dist/src/__tests__/e2e/provisioning.test.d.ts +0 -15
  194. package/dist/src/__tests__/e2e/provisioning.test.js +0 -123
  195. package/dist/src/__tests__/e2e/provisioning.test.js.map +0 -1
  196. package/dist/src/__tests__/handlers-unit.test.d.ts +0 -12
  197. package/dist/src/__tests__/handlers-unit.test.js +0 -505
  198. package/dist/src/__tests__/handlers-unit.test.js.map +0 -1
  199. package/dist/src/__tests__/namespace.test.d.ts +0 -1
  200. package/dist/src/__tests__/namespace.test.js +0 -114
  201. package/dist/src/__tests__/namespace.test.js.map +0 -1
  202. package/dist/src/__tests__/rerank.test.d.ts +0 -1
  203. package/dist/src/__tests__/rerank.test.js +0 -115
  204. package/dist/src/__tests__/rerank.test.js.map +0 -1
  205. package/dist/src/__tests__/utils.test.d.ts +0 -1
  206. package/dist/src/__tests__/utils.test.js +0 -83
  207. package/dist/src/__tests__/utils.test.js.map +0 -1
  208. package/dist/src/bench/cachly-bench.d.ts +0 -35
  209. package/dist/src/bench/cachly-bench.js +0 -182
  210. package/dist/src/bench/cachly-bench.js.map +0 -1
  211. package/dist/src/bench/fixtures.d.ts +0 -37
  212. package/dist/src/bench/fixtures.js +0 -225
  213. package/dist/src/bench/fixtures.js.map +0 -1
  214. package/dist/src/search.test.d.ts +0 -1
  215. package/dist/src/search.test.js +0 -713
  216. package/dist/src/search.test.js.map +0 -1
  217. package/eslint.config.js +0 -16
  218. package/glama.json +0 -36
  219. package/llms.txt +0 -155
  220. package/packages/telegram-notify/SPLIT_PLAN.md +0 -106
  221. package/packages/telegram-notify/client.ts +0 -88
  222. package/packages/telegram-notify/emojis.json +0 -22
  223. package/packages/telegram-notify/pyproject.toml +0 -17
  224. package/packages/telegram-notify/telegram_notify/__init__.py +0 -3
  225. package/packages/telegram-notify/telegram_notify/client.py +0 -87
  226. package/packages/telegram-notify/telegram_notify/emojis.json +0 -22
  227. package/scripts/e2e-run.sh +0 -160
  228. package/scripts/generate-icons.js +0 -28
  229. package/smithery.yaml +0 -45
  230. package/src/__tests__/auth.test.ts +0 -147
  231. package/src/__tests__/brain-flow.test.ts +0 -1472
  232. package/src/__tests__/confidence.test.ts +0 -285
  233. package/src/__tests__/e2e/api-auth.test.ts +0 -182
  234. package/src/__tests__/e2e/api-health.test.ts +0 -103
  235. package/src/__tests__/e2e/cli.test.ts +0 -228
  236. package/src/__tests__/e2e/config.ts +0 -53
  237. package/src/__tests__/e2e/funnel.test.ts +0 -99
  238. package/src/__tests__/e2e/mcp-tools.test.ts +0 -191
  239. package/src/__tests__/e2e/provisioning.test.ts +0 -128
  240. package/src/__tests__/handlers-unit.test.ts +0 -677
  241. package/src/__tests__/namespace.test.ts +0 -126
  242. package/src/__tests__/rerank.test.ts +0 -130
  243. package/src/__tests__/utils.test.ts +0 -81
  244. package/src/auth.ts +0 -46
  245. package/src/bench/cachly-bench.ts +0 -217
  246. package/src/bench/fixtures.ts +0 -256
  247. package/src/ckg.ts +0 -103
  248. package/src/confidence.ts +0 -38
  249. package/src/embeddings.ts +0 -217
  250. package/src/handlers/advanced.ts +0 -647
  251. package/src/handlers/brain.ts +0 -2622
  252. package/src/handlers/cache.ts +0 -633
  253. package/src/handlers/context.ts +0 -222
  254. package/src/handlers/fedbrain.ts +0 -1232
  255. package/src/handlers/instances.ts +0 -180
  256. package/src/handlers/roadmap.ts +0 -201
  257. package/src/handlers/syndicate.ts +0 -460
  258. package/src/handlers/tco.ts +0 -345
  259. package/src/handlers/team.ts +0 -1249
  260. package/src/index.ts +0 -2815
  261. package/src/namespace.ts +0 -128
  262. package/src/notifier.ts +0 -5
  263. package/src/rerank.ts +0 -148
  264. package/src/search.test.ts +0 -848
  265. package/src/search.ts +0 -1781
  266. package/src/tools.ts +0 -2056
  267. package/src/utils.ts +0 -90
  268. package/test-features.cjs +0 -23
  269. package/tsconfig.json +0 -16
  270. package/vitest.config.ts +0 -14
@@ -1,346 +0,0 @@
1
- import React, { useEffect, useState } from "react";
2
- import {
3
- ActivityIndicator, BackHandler, FlatList, KeyboardAvoidingView,
4
- Platform, Share, StyleSheet, Text, TouchableOpacity, View,
5
- } from "react-native";
6
- import ConfettiCannon from "../../../components/ConfettiCannon";
7
- import { useLocalSearchParams, useRouter, useFocusEffect } from "expo-router";
8
- import ConfirmDialog from "../../../components/ConfirmDialog";
9
- import { useSafeAreaInsets } from "react-native-safe-area-context";
10
- import * as DocumentPicker from "expo-document-picker";
11
- import * as ImagePicker from "expo-image-picker";
12
- import { useTripItems, useTrips } from "../../../hooks/useTrips";
13
- import { ApiError, parseFile, TripItem } from "../../../lib/api";
14
- import SwipeableTimelineItem from "../../../components/SwipeableTimelineItem";
15
- import TimelineItemDetail from "../../../components/TimelineItemDetail";
16
- import ImportSheet from "../../../components/ImportSheet";
17
- import FileUploadButton from "../../../components/FileUploadButton";
18
- import { TimelineItemSkeleton } from "../../../components/Skeleton";
19
- import { haptics } from "../../../lib/haptics";
20
- import { useToast } from "../../../components/ToastContext";
21
- import { scheduleItemReminder } from "../../../lib/notifications";
22
- import { getLocalItems } from "../../../lib/db";
23
- import { format, parseISO } from "date-fns";
24
- import { de } from "date-fns/locale";
25
-
26
- export default function TripDetailScreen() {
27
- const { id, sharedUri, sharedMime, sharedName } = useLocalSearchParams<{
28
- id: string;
29
- sharedUri?: string;
30
- sharedMime?: string;
31
- sharedName?: string;
32
- }>();
33
- const router = useRouter();
34
- const insets = useSafeAreaInsets();
35
- const { items, loading, refresh, deleteItem } = useTripItems(id);
36
- const { deleteTrip, trips } = useTrips();
37
- const { showToast } = useToast();
38
- const [parsing, setParsing] = useState(false);
39
- const [showConfetti, setShowConfetti] = useState(false);
40
- const [selectedItem, setSelectedItem] = useState<TripItem | null>(null);
41
- const [importVisible, setImportVisible] = useState(false);
42
- const [dialog, setDialog] = useState<{ title: string; message?: string; onConfirm: () => void; destructive?: boolean } | null>(null);
43
-
44
- useFocusEffect(
45
- React.useCallback(() => {
46
- const handler = BackHandler.addEventListener('hardwareBackPress', () => {
47
- if (parsing) {
48
- setDialog({ title: 'Upload läuft', message: 'Ein Dokument wird gerade verarbeitet. Trotzdem zurück?', onConfirm: () => router.back(), destructive: true });
49
- return true;
50
- }
51
- return false;
52
- });
53
- return () => handler.remove();
54
- }, [parsing])
55
- );
56
-
57
- useEffect(() => {
58
- if (sharedUri) {
59
- parseAndRefresh(sharedUri, sharedMime ?? "application/octet-stream", sharedName ?? "shared-file");
60
- }
61
- }, [sharedUri]);
62
-
63
- async function uploadDocument() {
64
- const result = await DocumentPicker.getDocumentAsync({ type: ["application/pdf", "image/*", "text/*"] });
65
- if (result.canceled) return;
66
- const asset = result.assets[0];
67
- await parseAndRefresh(asset.uri, asset.mimeType ?? "application/octet-stream", asset.name);
68
- }
69
-
70
- async function uploadScreenshot() {
71
- const result = await ImagePicker.launchImageLibraryAsync({ mediaTypes: ImagePicker.MediaTypeOptions.Images, quality: 0.9 });
72
- if (result.canceled) return;
73
- const asset = result.assets[0];
74
- await parseAndRefresh(asset.uri, "image/jpeg", "screenshot.jpg");
75
- }
76
-
77
- async function parseAndRefresh(uri: string, mime: string, name: string) {
78
- setParsing(true);
79
- await haptics.confirm();
80
- // Capture existing item IDs before upload so we can identify the new item
81
- // after refresh — and only schedule a reminder for that one item.
82
- // Without this, every upload would re-schedule reminders for ALL existing
83
- // items, causing duplicate (or spam) notifications.
84
- const itemIdsBefore = new Set(getLocalItems(id).map((i) => i.id));
85
- const currentTrip = trips.find((t) => t.id === id);
86
- const tripName = currentTrip?.name ?? "Dein Trip";
87
- try {
88
- await parseFile(uri, mime, name, id);
89
- await haptics.success();
90
- await refresh();
91
- // After refresh, SQLite is up-to-date. Find only the newly added item(s).
92
- const allItems = getLocalItems(id);
93
- for (const item of allItems) {
94
- if (!itemIdsBefore.has(item.id) && item.event_at) {
95
- await scheduleItemReminder(id, tripName, item.id, item.title, item.event_at);
96
- }
97
- }
98
- setShowConfetti(true);
99
- setTimeout(() => setShowConfetti(false), 1500);
100
- } catch (err) {
101
- await haptics.error();
102
- if (err instanceof ApiError && err.status === 429) {
103
- showToast("Tageslimit erreicht (50 Parses/Tag). Upgrade auf Pro.", "warning");
104
- } else if (err instanceof ApiError && err.status === 408) {
105
- showToast("Timeout — Ollama antwortet nicht. Bitte warte und versuche es erneut.", "error");
106
- } else if (err instanceof ApiError && err.status === 413) {
107
- showToast("Datei zu groß (max. 10 MB).", "error");
108
- } else if (err instanceof ApiError && err.status === 415) {
109
- showToast("Dateityp nicht unterstützt (PDF, Bild oder Text).", "error");
110
- } else {
111
- showToast("Datei konnte nicht verarbeitet werden. Prüfe Ollama.", "error");
112
- }
113
- } finally {
114
- setParsing(false);
115
- }
116
- }
117
-
118
- function handleDeleteItem(itemId: string) {
119
- setDialog({
120
- title: "Eintrag löschen?",
121
- message: "Dieser Eintrag wird dauerhaft entfernt.",
122
- destructive: true,
123
- onConfirm: async () => {
124
- await haptics.warning();
125
- await deleteItem(itemId);
126
- },
127
- });
128
- }
129
-
130
- function handleDeleteTrip() {
131
- setDialog({
132
- title: "Trip löschen?",
133
- message: "Alle Einträge und Daten werden gelöscht.",
134
- destructive: true,
135
- onConfirm: async () => {
136
- await haptics.error();
137
- await deleteTrip(id);
138
- router.back();
139
- },
140
- });
141
- }
142
-
143
- async function handleTapItem(item: TripItem) {
144
- await haptics.tap();
145
- setSelectedItem(item);
146
- }
147
-
148
- async function handleShareTrip() {
149
- const currentTrip = trips.find(t => t.id === id);
150
- const tripName = currentTrip?.name ?? "Mein Trip";
151
- const lines: string[] = [];
152
-
153
- lines.push(`✈️ Mein Trip: ${tripName}`);
154
-
155
- if (currentTrip?.start_date) {
156
- const startStr = format(parseISO(currentTrip.start_date), "dd. MMM", { locale: de });
157
- if (currentTrip.end_date) {
158
- const endStr = format(parseISO(currentTrip.end_date), "dd. MMM yyyy", { locale: de });
159
- const diffMs = new Date(currentTrip.end_date).getTime() - new Date(currentTrip.start_date).getTime();
160
- const days = Math.round(diffMs / (1000 * 60 * 60 * 24));
161
- lines.push(`📅 ${startStr} → ${endStr} (${days} Tage)`);
162
- } else {
163
- lines.push(`📅 ${startStr}`);
164
- }
165
- }
166
-
167
- if (items.length > 0) {
168
- const types = Array.from(new Set(items.map(i => i.type).filter(Boolean))) as string[];
169
- const capitalizedTypes = types.map(t => t.charAt(0).toUpperCase() + t.slice(1));
170
- const displayTypes = capitalizedTypes.length > 3
171
- ? `${capitalizedTypes.slice(0, 3).join(", ")} + mehr`
172
- : capitalizedTypes.join(", ");
173
- lines.push(`📋 ${items.length} Einträge${displayTypes ? ` (${displayTypes})` : ""}`);
174
- }
175
-
176
- const refs = items.map(i => i.booking_ref).filter(Boolean) as string[];
177
- if (refs.length > 0) {
178
- const displayRefs = refs.length > 3
179
- ? `${refs.slice(0, 3).join(", ")} + mehr`
180
- : refs.join(", ");
181
- lines.push(`🔑 ${displayRefs}`);
182
- }
183
-
184
- lines.push("");
185
- lines.push("Erstellt mit Travel Chaos Organizer");
186
-
187
- await Share.share({ message: lines.join("\n") });
188
- }
189
-
190
- return (
191
- <KeyboardAvoidingView style={s.container} behavior={Platform.OS === "ios" ? "padding" : "height"}>
192
- <View style={[s.header, { paddingTop: insets.top + 8 }]}>
193
- <TouchableOpacity
194
- onPress={() => {
195
- if (parsing) {
196
- setDialog({ title: 'Upload läuft', message: 'Ein Dokument wird gerade verarbeitet. Trotzdem zurück?', onConfirm: () => router.back(), destructive: true });
197
- } else {
198
- router.back();
199
- }
200
- }}
201
- style={s.back}
202
- hitSlop={{ top: 12, bottom: 12, left: 12, right: 12 }}
203
- accessibilityLabel="Zurück"
204
- accessibilityRole="button"
205
- >
206
- <Text style={s.backText}>← Zurück</Text>
207
- </TouchableOpacity>
208
-
209
- <Text style={s.headerTitle} numberOfLines={1}>
210
- {trips.find((t) => t.id === id)?.name ?? "Timeline"}
211
- </Text>
212
-
213
- <TouchableOpacity
214
- onPress={handleShareTrip}
215
- style={s.shareBtn}
216
- hitSlop={{ top: 12, bottom: 12, left: 12, right: 12 }}
217
- accessibilityLabel="Trip teilen"
218
- accessibilityRole="button"
219
- >
220
- <Text style={s.shareBtnText}>↗</Text>
221
- </TouchableOpacity>
222
-
223
- <TouchableOpacity
224
- onPress={handleDeleteTrip}
225
- style={s.deleteBtn}
226
- hitSlop={{ top: 12, bottom: 12, left: 12, right: 12 }}
227
- accessibilityLabel="Trip löschen"
228
- accessibilityRole="button"
229
- >
230
- <Text style={s.deleteBtnText}>🗑️</Text>
231
- </TouchableOpacity>
232
- </View>
233
-
234
- {parsing && (
235
- <View style={s.parsingBanner}>
236
- <ActivityIndicator color="#4f46e5" size="small" />
237
- <Text style={s.parsingText}>Ollama analysiert Dokument…</Text>
238
- </View>
239
- )}
240
-
241
- <FlatList
242
- data={items}
243
- keyExtractor={(i) => i.id}
244
- contentContainerStyle={items.length === 0 ? s.emptyContainer : s.list}
245
- refreshing={loading}
246
- onRefresh={refresh}
247
- ListHeaderComponent={
248
- items.length > 0
249
- ? <Text style={s.hint}>Tippen für Details · ← Wischen zum Löschen</Text>
250
- : null
251
- }
252
- ListEmptyComponent={
253
- loading
254
- ? <View style={s.list}>{[1, 2, 3].map(k => <TimelineItemSkeleton key={k} />)}</View>
255
- : <View style={s.empty}>
256
- <Text style={s.emptyIcon}>📂</Text>
257
- <Text style={s.emptyTitle}>Noch keine Einträge</Text>
258
- <Text style={s.emptySub}>Lade ein Dokument hoch oder füge Text ein.</Text>
259
- </View>
260
- }
261
- renderItem={({ item }) => (
262
- <TouchableOpacity
263
- onPress={() => handleTapItem(item)}
264
- activeOpacity={0.85}
265
- accessibilityLabel={`${item.title} — Details anzeigen`}
266
- accessibilityRole="button"
267
- >
268
- <SwipeableTimelineItem
269
- item={item}
270
- onDelete={() => handleDeleteItem(item.id)}
271
- />
272
- </TouchableOpacity>
273
- )}
274
- />
275
-
276
- <View style={[s.uploadBar, { paddingBottom: insets.bottom + 8 }]}>
277
- <FileUploadButton icon="📄" label="PDF / Datei" onPress={uploadDocument} disabled={parsing} />
278
- <FileUploadButton icon="🖼️" label="Screenshot" onPress={uploadScreenshot} disabled={parsing} />
279
- <FileUploadButton
280
- icon="📝"
281
- label="Text / E-Mail"
282
- onPress={() => setImportVisible(true)}
283
- disabled={parsing}
284
- />
285
- </View>
286
-
287
- {/* Timeline item detail */}
288
- <TimelineItemDetail
289
- item={selectedItem}
290
- onClose={() => setSelectedItem(null)}
291
- />
292
-
293
- {/* In-app text/email import */}
294
- <ImportSheet
295
- visible={importVisible}
296
- onClose={() => setImportVisible(false)}
297
- tripId={id}
298
- onSuccess={refresh}
299
- />
300
-
301
- <ConfirmDialog
302
- visible={!!dialog}
303
- title={dialog?.title ?? ""}
304
- message={dialog?.message}
305
- actions={[
306
- {
307
- label: dialog?.destructive ? "Ja, löschen" : "Ja, zurück",
308
- style: "destructive",
309
- onPress: () => { setDialog(null); dialog?.onConfirm(); },
310
- },
311
- { label: "Abbrechen", style: "cancel", onPress: () => setDialog(null) },
312
- ]}
313
- />
314
-
315
- <ConfettiCannon visible={showConfetti} />
316
- </KeyboardAvoidingView>
317
- );
318
- }
319
-
320
- const s = StyleSheet.create({
321
- container: { flex: 1, backgroundColor: "#0f0f1a" },
322
- header: {
323
- flexDirection: "row", alignItems: "center", paddingHorizontal: 16,
324
- paddingBottom: 12, backgroundColor: "#1a1a2e",
325
- },
326
- back: { paddingVertical: 4 },
327
- backText: { color: "#4f46e5", fontSize: 15 },
328
- headerTitle: { flex: 1, color: "#fff", fontSize: 18, fontWeight: "700", textAlign: "center" },
329
- deleteBtn: { padding: 4 },
330
- deleteBtnText: { fontSize: 18 },
331
- shareBtn: { padding: 4, marginRight: 8 },
332
- shareBtnText: { color: "#a5b4fc", fontSize: 20, fontWeight: "300" },
333
- parsingBanner: { flexDirection: "row", alignItems: "center", gap: 8, backgroundColor: "#4f46e522", padding: 10, paddingHorizontal: 16 },
334
- parsingText: { color: "#a5b4fc", fontSize: 14 },
335
- hint: { color: "#3a3a5e", fontSize: 12, textAlign: "center", marginBottom: 8 },
336
- list: { padding: 16, gap: 1 },
337
- emptyContainer: { flex: 1 },
338
- empty: { flex: 1, alignItems: "center", justifyContent: "center", padding: 48 },
339
- emptyIcon: { fontSize: 56, marginBottom: 16 },
340
- emptyTitle: { fontSize: 20, fontWeight: "700", color: "#fff", marginBottom: 8 },
341
- emptySub: { fontSize: 14, color: "#6666aa", textAlign: "center" },
342
- uploadBar: {
343
- flexDirection: "row", gap: 8, padding: 12,
344
- backgroundColor: "#1a1a2e", borderTopWidth: 1, borderTopColor: "#2a2a4e",
345
- },
346
- });