[{"data":1,"prerenderedAt":19856},["ShallowReactive",2],{"navigation_docs":3,"-react-native-version2-offline-first-sync":3728,"-react-native-version2-offline-first-sync-surround":19851},[4,1707,1912,2366,2547,2673,2880,3002,3052,3109,3143,3269,3346,3360,3495,3512,3525,3671,3724],{"title":5,"icon":6,"path":7,"stem":8,"children":9},"C#","i-devicon-csharp","\u002Fcsharp","01.csharp",[10,13,60,90,120,202,219,253,379,404,457,650,1364,1654,1703],{"title":11,"path":7,"stem":12},"C# та .NET","01.csharp\u002Findex",{"title":14,"icon":15,"path":16,"stem":17,"children":18,"page":59},"Fundamentals","i-lucide-book-open","\u002Fcsharp\u002Ffundamentals","01.csharp\u002F01.fundamentals",[19,23,27,31,35,39,43,47,51,55],{"title":20,"path":21,"stem":22},"Вступ до екосистеми .NET","\u002Fcsharp\u002Ffundamentals\u002Fintroduction-to-ecosystem","01.csharp\u002F01.fundamentals\u002F01.introduction-to-ecosystem",{"title":24,"path":25,"stem":26},"Структура програми на C#","\u002Fcsharp\u002Ffundamentals\u002Fprogram-structure","01.csharp\u002F01.fundamentals\u002F02.program-structure",{"title":28,"path":29,"stem":30},"Змінні та Типи Даних","\u002Fcsharp\u002Ffundamentals\u002Fvariables-data-types","01.csharp\u002F01.fundamentals\u002F03.variables-data-types",{"title":32,"path":33,"stem":34},"Масиви","\u002Fcsharp\u002Ffundamentals\u002Farrays","01.csharp\u002F01.fundamentals\u002F04.arrays",{"title":36,"path":37,"stem":38},"Strings & Text Handling","\u002Fcsharp\u002Ffundamentals\u002Fstrings-text-handling","01.csharp\u002F01.fundamentals\u002F05.strings-text-handling",{"title":40,"path":41,"stem":42},"Дати і Час","\u002Fcsharp\u002Ffundamentals\u002Fdates-time-handling","01.csharp\u002F01.fundamentals\u002F06.dates-time-handling",{"title":44,"path":45,"stem":46},"Потік Керування","\u002Fcsharp\u002Ffundamentals\u002Fcontrol-flow","01.csharp\u002F01.fundamentals\u002F07.control-flow",{"title":48,"path":49,"stem":50},"Методи","\u002Fcsharp\u002Ffundamentals\u002Fmethods","01.csharp\u002F01.fundamentals\u002F08.methods",{"title":52,"path":53,"stem":54},"Основи Відлагодження","\u002Fcsharp\u002Ffundamentals\u002Fdebugging-basics","01.csharp\u002F01.fundamentals\u002F09.debugging-basics",{"title":56,"path":57,"stem":58},"Інтерактивна Консоль (Classic)","\u002Fcsharp\u002Ffundamentals\u002Finteractive-console","01.csharp\u002F01.fundamentals\u002F10.interactive-console",false,{"title":61,"icon":62,"path":63,"stem":64,"children":65,"page":59},"OOP","i-lucide-box","\u002Fcsharp\u002Foop","01.csharp\u002F02.oop",[66,70,74,78,82,86],{"title":67,"path":68,"stem":69},"Package Management (Управління Пакетами)","\u002Fcsharp\u002Foop\u002Fpackage-management","01.csharp\u002F02.oop\u002F01.package-management",{"title":71,"path":72,"stem":73},"Класи та Об'єкти","\u002Fcsharp\u002Foop\u002Fclasses-objects","01.csharp\u002F02.oop\u002F02.classes-objects",{"title":75,"path":76,"stem":77},"Властивості та Поля","\u002Fcsharp\u002Foop\u002Fproperties-fields","01.csharp\u002F02.oop\u002F03.properties-fields",{"title":79,"path":80,"stem":81},"Стовпи ООП","\u002Fcsharp\u002Foop\u002Foop-pillars","01.csharp\u002F02.oop\u002F04.oop-pillars",{"title":83,"path":84,"stem":85},"Advanced Types","\u002Fcsharp\u002Foop\u002Fadvanced-types","01.csharp\u002F02.oop\u002F05.advanced-types",{"title":87,"path":88,"stem":89},"Namespaces (Простори Імен)","\u002Fcsharp\u002Foop\u002Fnamespaces","01.csharp\u002F02.oop\u002F06.namespaces",{"title":91,"icon":92,"path":93,"stem":94,"children":95,"page":59},"Advanced Core","i-lucide-zap","\u002Fcsharp\u002Fadvanced-core","01.csharp\u002F03.advanced-core",[96,100,104,108,112,116],{"title":97,"path":98,"stem":99},"Generics (Узагальнення)","\u002Fcsharp\u002Fadvanced-core\u002Fgenerics","01.csharp\u002F03.advanced-core\u002F01.generics",{"title":101,"path":102,"stem":103},"Делегати, Події та Лямбда-вирази","\u002Fcsharp\u002Fadvanced-core\u002Fdelegates-events-lambdas","01.csharp\u002F03.advanced-core\u002F02.delegates-events-lambdas",{"title":105,"path":106,"stem":107},"Interfaces Deep Dive (Інтерфейси: Поглиблений Розгляд)","\u002Fcsharp\u002Fadvanced-core\u002Finterfaces-deep-dive","01.csharp\u002F03.advanced-core\u002F03.interfaces-deep-dive",{"title":109,"path":110,"stem":111},"Обробка Винятків","\u002Fcsharp\u002Fadvanced-core\u002Fexception-handling","01.csharp\u002F03.advanced-core\u002F04.exception-handling",{"title":113,"path":114,"stem":115},"Pattern Matching","\u002Fcsharp\u002Fadvanced-core\u002Fpattern-matching","01.csharp\u002F03.advanced-core\u002F05.pattern-matching",{"title":117,"path":118,"stem":119},"Додаткові Можливості C#","\u002Fcsharp\u002Fadvanced-core\u002Fadditional-features","01.csharp\u002F03.advanced-core\u002F06.additional-features",{"title":121,"icon":122,"path":123,"stem":124,"children":125,"page":59},"Architecture Best Practices","i-lucide-building-2","\u002Fcsharp\u002Farchitecture-best-practices","01.csharp\u002F04.architecture-best-practices",[126,130,149,153,157,161,165,169],{"title":127,"path":128,"stem":129},"Software Design Principles (Частина 1)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fsoftware-design-principles","01.csharp\u002F04.architecture-best-practices\u002F01.software-design-principles",{"title":131,"icon":132,"path":133,"stem":134,"children":135,"page":59},"Design Patterns","i-lucide-folder","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns",[136],{"title":137,"icon":132,"path":138,"stem":139,"children":140,"page":59},"Creational","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns\u002Fcreational","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns\u002Fcreational",[141,145],{"title":142,"path":143,"stem":144},"Singleton (Одинак)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns\u002Fcreational\u002Fsingleton","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns\u002Fcreational\u002F01.singleton",{"title":146,"path":147,"stem":148},"Builder (Будівельник)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdesign-patterns\u002Fcreational\u002Fbuilder","01.csharp\u002F04.architecture-best-practices\u002F02.design-patterns\u002Fcreational\u002F02.builder",{"title":150,"path":151,"stem":152},"Building Professional CLIs","\u002Fcsharp\u002Farchitecture-best-practices\u002Fbuilding-professional-clis","01.csharp\u002F04.architecture-best-practices\u002F03.building-professional-clis",{"title":154,"path":155,"stem":156},"Validation & Flow Control","\u002Fcsharp\u002Farchitecture-best-practices\u002Fvalidation-flow-control","01.csharp\u002F04.architecture-best-practices\u002F04.validation-flow-control",{"title":158,"path":159,"stem":160},"The Modern .NET Host (Microsoft.Extensions)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fmodern-dotnet-host","01.csharp\u002F04.architecture-best-practices\u002F05.modern-dotnet-host",{"title":162,"path":163,"stem":164},"Data Mapper: Repository та DAO патерни (Частина 1)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdata-mapper-part1","01.csharp\u002F04.architecture-best-practices\u002F06.data-mapper-part1",{"title":166,"path":167,"stem":168},"Data Mapper: Repository та DAO патерни (Частина 2)","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdata-mapper-part2","01.csharp\u002F04.architecture-best-practices\u002F07.data-mapper-part2",{"title":170,"icon":132,"path":171,"stem":172,"children":173,"page":59},"Di Ioc","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc",[174,178,182,186,190,194,198],{"title":175,"path":176,"stem":177},"Проблема залежностей та Інверсія Контролю","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fthe-dependency-problem","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F01.the-dependency-problem",{"title":179,"path":180,"stem":181},"Будуємо власний Service Container","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fbuild-your-own-container","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F02.build-your-own-container",{"title":183,"path":184,"stem":185},"Service Locator: Паттерн та Анти-паттерн","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fservice-locator-pattern","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F03.service-locator-pattern",{"title":187,"path":188,"stem":189},"Паттерни Dependency Injection","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fdependency-injection-patterns","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F04.dependency-injection-patterns",{"title":191,"path":192,"stem":193},"Microsoft DI: IServiceCollection та IServiceProvider","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fmicrosoft-di-deep-dive","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F05.microsoft-di-deep-dive",{"title":195,"path":196,"stem":197},"Service Lifetimes та Scopes","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fservice-lifetimes-and-scopes","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F06.service-lifetimes-and-scopes",{"title":199,"path":200,"stem":201},"DI Анти-паттерни та Найкращі Практики","\u002Fcsharp\u002Farchitecture-best-practices\u002Fdi-ioc\u002Fdi-anti-patterns-and-best-practices","01.csharp\u002F04.architecture-best-practices\u002F08.di-ioc\u002F07.di-anti-patterns-and-best-practices",{"title":203,"icon":132,"path":204,"stem":205,"children":206,"page":59},"Standard Library","\u002Fcsharp\u002Fstandard-library","01.csharp\u002F05.standard-library",[207,211,215],{"title":208,"path":209,"stem":210},"Collections (Колекції)","\u002Fcsharp\u002Fstandard-library\u002Fcollections","01.csharp\u002F05.standard-library\u002F01.collections",{"title":212,"path":213,"stem":214},"High Performance Types (Високопродуктивні Типи)","\u002Fcsharp\u002Fstandard-library\u002Fhigh-performance-types","01.csharp\u002F05.standard-library\u002F02.high-performance-types",{"title":216,"path":217,"stem":218},"LINQ (Language Integrated Query)","\u002Fcsharp\u002Fstandard-library\u002Flinq","01.csharp\u002F05.standard-library\u002F03.linq",{"title":220,"icon":221,"path":222,"stem":223,"children":224,"page":59},"System Internals Concurrency","i-lucide-server","\u002Fcsharp\u002Fsystem-internals-concurrency","01.csharp\u002F06.system-internals-concurrency",[225,229,233,237,241,245,249],{"title":226,"path":227,"stem":228},"Memory Management","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fmemory-management","01.csharp\u002F06.system-internals-concurrency\u002F01.memory-management",{"title":230,"path":231,"stem":232},"Reflection API: System.Type та Метадані","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Freflection-fundamentals","01.csharp\u002F06.system-internals-concurrency\u002F02.reflection-fundamentals",{"title":234,"path":235,"stem":236},"Attributes та Dynamic Language Runtime","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fattributes-dynamic","01.csharp\u002F06.system-internals-concurrency\u002F03.attributes-dynamic",{"title":238,"path":239,"stem":240},"Expression Trees: Швидка Альтернатива Рефлексії","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fexpression-trees-compiled","01.csharp\u002F06.system-internals-concurrency\u002F04.expression-trees-compiled",{"title":242,"path":243,"stem":244},"Source Generators: Compile-Time Code Generation","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fsource-generators","01.csharp\u002F06.system-internals-concurrency\u002F05.source-generators",{"title":246,"path":247,"stem":248},"Multithreading Fundamentals","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fmultithreading-fundamentals","01.csharp\u002F06.system-internals-concurrency\u002F06.multithreading-fundamentals",{"title":250,"path":251,"stem":252},"Synchronization Primitives","\u002Fcsharp\u002Fsystem-internals-concurrency\u002Fsynchronization-primitives","01.csharp\u002F06.system-internals-concurrency\u002F07.synchronization-primitives",{"title":254,"icon":255,"path":256,"stem":257,"children":258,"page":59},"System Programming Windows","i-lucide-cpu","\u002Fcsharp\u002Fsystem-programming-windows","01.csharp\u002F07.system-programming-windows",[259,263,267,271,275,279,283,287,291,295,299,303,307,311,315,319,323,327,331,335,339,343,347,351,355,359,363,367,371,375],{"title":260,"path":261,"stem":262},"Як Працює Операційна Система","\u002Fcsharp\u002Fsystem-programming-windows\u002Fhow-os-works","01.csharp\u002F07.system-programming-windows\u002F01.how-os-works",{"title":264,"path":265,"stem":266},"Процеси в .NET — API та Запуск","\u002Fcsharp\u002Fsystem-programming-windows\u002Fprocesses-in-dotnet","01.csharp\u002F07.system-programming-windows\u002F02.processes-in-dotnet",{"title":268,"path":269,"stem":270},"Процеси в .NET — IPC та Міжпроцесна Комунікація","\u002Fcsharp\u002Fsystem-programming-windows\u002F02a.processes-ipc","01.csharp\u002F07.system-programming-windows\u002F02a.processes-ipc",{"title":272,"path":273,"stem":274},"Application Domains та Збірки — AppDomain і AssemblyLoadContext","\u002Fcsharp\u002Fsystem-programming-windows\u002Fappdomains-assemblies","01.csharp\u002F07.system-programming-windows\u002F03.appdomains-assemblies",{"title":276,"path":277,"stem":278},"Application Domains та Збірки — Plug-in Система з Hot-Reload","\u002Fcsharp\u002Fsystem-programming-windows\u002F03a.appdomains-plugin-system","01.csharp\u002F07.system-programming-windows\u002F03a.appdomains-plugin-system",{"title":280,"path":281,"stem":282},"Потоки — Основи та API Thread","\u002Fcsharp\u002Fsystem-programming-windows\u002Fthread-fundamentals","01.csharp\u002F07.system-programming-windows\u002F04.thread-fundamentals",{"title":284,"path":285,"stem":286},"Потоки — Lifecycle, Пріоритети та Безпечне Завершення","\u002Fcsharp\u002Fsystem-programming-windows\u002F04a.thread-lifecycle-priorities","01.csharp\u002F07.system-programming-windows\u002F04a.thread-lifecycle-priorities",{"title":288,"path":289,"stem":290},"Проблеми Спільного Стану — Race Condition та Data Race","\u002Fcsharp\u002Fsystem-programming-windows\u002Fshared-state-problems","01.csharp\u002F07.system-programming-windows\u002F05.shared-state-problems",{"title":292,"path":293,"stem":294},"Проблеми Спільного Стану — Memory Model та volatile","\u002Fcsharp\u002Fsystem-programming-windows\u002F05a.shared-state-memory-model","01.csharp\u002F07.system-programming-windows\u002F05a.shared-state-memory-model",{"title":296,"path":297,"stem":298},"Синхронізація — Monitor, lock та еволюція примітивів","\u002Fcsharp\u002Fsystem-programming-windows\u002Fsynchronization-fundamentals","01.csharp\u002F07.system-programming-windows\u002F06.synchronization-fundamentals",{"title":300,"path":301,"stem":302},"Синхронізація — Наскрізний Приклад та Deadlock Detection","\u002Fcsharp\u002Fsystem-programming-windows\u002F06a.synchronization-walkthrough","01.csharp\u002F07.system-programming-windows\u002F06a.synchronization-walkthrough",{"title":304,"path":305,"stem":306},"Синхронізація — Mutex, Semaphore та Event-Based Primitives","\u002Fcsharp\u002Fsystem-programming-windows\u002Fsynchronization-advanced","01.csharp\u002F07.system-programming-windows\u002F07.synchronization-advanced",{"title":308,"path":309,"stem":310},"Синхронізація — Interlocked, Volatile та Lock-Free Структури","\u002Fcsharp\u002Fsystem-programming-windows\u002F07a.synchronization-advanced-walkthrough","01.csharp\u002F07.system-programming-windows\u002F07a.synchronization-advanced-walkthrough",{"title":312,"path":313,"stem":314},"Interlocked, CAS та Lock-Free Структури","\u002Fcsharp\u002Fsystem-programming-windows\u002Finterlocked-cas-lockfree","01.csharp\u002F07.system-programming-windows\u002F08.interlocked-cas-lockfree",{"title":316,"path":317,"stem":318},"Volatile, Memory Model та Spinning","\u002Fcsharp\u002Fsystem-programming-windows\u002F08a.volatile-memory-model","01.csharp\u002F07.system-programming-windows\u002F08a.volatile-memory-model",{"title":320,"path":321,"stem":322},"ThreadPool — Пул Потоків для Ефективного Виконання","\u002Fcsharp\u002Fsystem-programming-windows\u002Fthread-pool","01.csharp\u002F07.system-programming-windows\u002F09.thread-pool",{"title":324,"path":325,"stem":326},"ThreadPool — Просунуті Сценарії та Внутрішня Будова","\u002Fcsharp\u002Fsystem-programming-windows\u002F09a.thread-pool-advanced","01.csharp\u002F07.system-programming-windows\u002F09a.thread-pool-advanced",{"title":328,"path":329,"stem":330},"Concurrent та Immutable Collections","\u002Fcsharp\u002Fsystem-programming-windows\u002Fconcurrent-collections","01.csharp\u002F07.system-programming-windows\u002F10.concurrent-collections",{"title":332,"path":333,"stem":334},"TPL, Task та Композиція — Від Thread до Task","\u002Fcsharp\u002Fsystem-programming-windows\u002Ftpl-parallel-plinq","01.csharp\u002F07.system-programming-windows\u002F11.tpl-parallel-plinq",{"title":336,"path":337,"stem":338},"Parallel Class та PLINQ — Data Parallelism","\u002Fcsharp\u002Fsystem-programming-windows\u002F11a.tpl-parallel-plinq-advanced","01.csharp\u002F07.system-programming-windows\u002F11a.tpl-parallel-plinq-advanced",{"title":340,"path":341,"stem":342},"Async\u002FAwait — Фундамент Асинхронного Програмування","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-fundamentals","01.csharp\u002F07.system-programming-windows\u002F12.async-fundamentals",{"title":344,"path":345,"stem":346},"SynchronizationContext та ConfigureAwait — Контекст Виконання","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-context-configureawait","01.csharp\u002F07.system-programming-windows\u002F13.async-context-configureawait",{"title":348,"path":349,"stem":350},"Async — Просунуті Паттерни","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-advanced","01.csharp\u002F07.system-programming-windows\u002F14.async-advanced",{"title":352,"path":353,"stem":354},"System.Threading.Channels — Async Producer-Consumer","\u002Fcsharp\u002Fsystem-programming-windows\u002Fchannels","01.csharp\u002F07.system-programming-windows\u002F15.channels",{"title":356,"path":357,"stem":358},"Асинхронна Синхронізація","\u002Fcsharp\u002Fsystem-programming-windows\u002Fasync-synchronization","01.csharp\u002F07.system-programming-windows\u002F16.async-synchronization",{"title":360,"path":361,"stem":362},"Unsafe Code та Вказівники","\u002Fcsharp\u002Fsystem-programming-windows\u002Funsafe-code","01.csharp\u002F07.system-programming-windows\u002F17.unsafe-code",{"title":364,"path":365,"stem":366},"P\u002FInvoke та Windows API — Міст між .NET та Native Code","\u002Fcsharp\u002Fsystem-programming-windows\u002Fpinvoke-winapi","01.csharp\u002F07.system-programming-windows\u002F18.pinvoke-winapi",{"title":368,"path":369,"stem":370},"Реєстр Windows — Центральна База Конфігурації Системи","\u002Fcsharp\u002Fsystem-programming-windows\u002Fwindows-registry","01.csharp\u002F07.system-programming-windows\u002F19.windows-registry",{"title":372,"path":373,"stem":374},"Windows Hooks, Hotkeys та Services — Глибока Інтеграція з ОС","\u002Fcsharp\u002Fsystem-programming-windows\u002Fwindows-hooks-services","01.csharp\u002F07.system-programming-windows\u002F20.windows-hooks-services",{"title":376,"path":377,"stem":378},"Системне Програмування C# (Windows) — 07.system-programming-windows","\u002Fcsharp\u002Fsystem-programming-windows\u002Fimplementation_plan","01.csharp\u002F07.system-programming-windows\u002Fimplementation_plan",{"title":380,"icon":132,"path":381,"stem":382,"children":383,"page":59},"Io","\u002Fcsharp\u002Fio","01.csharp\u002F08.io",[384,388,392,396,400],{"title":385,"path":386,"stem":387},"8.1.1. Основи роботи з файловою системою","\u002Fcsharp\u002Fio\u002Ffile-system-basics","01.csharp\u002F08.io\u002F01.file-system-basics",{"title":389,"path":390,"stem":391},"8.1.2. Потоки (Streams) та Серіалізація Даних","\u002Fcsharp\u002Fio\u002Fstreams-serialization","01.csharp\u002F08.io\u002F02.streams-serialization",{"title":393,"path":394,"stem":395},"8.2.1. JSON Serialization з System.Text.Json","\u002Fcsharp\u002Fio\u002Fjson-serialization","01.csharp\u002F08.io\u002F03.json-serialization",{"title":397,"path":398,"stem":399},"8.2.2. XML Serialization та LINQ to XML","\u002Fcsharp\u002Fio\u002Fxml-serialization","01.csharp\u002F08.io\u002F04.xml-serialization",{"title":401,"path":402,"stem":403},"8.2.3. Binary Serialization: MessagePack та Protocol Buffers","\u002Fcsharp\u002Fio\u002Fbinary-serialization","01.csharp\u002F08.io\u002F05.binary-serialization",{"title":405,"icon":132,"path":406,"stem":407,"children":408,"page":59},"Ado Net","\u002Fcsharp\u002Fado-net","01.csharp\u002F09.ado-net",[409,413,417,421,425,429,433,437,441,445,449,453],{"title":410,"path":411,"stem":412},"9.1. Введення в ADO.NET","\u002Fcsharp\u002Fado-net\u002Fintroduction-to-adonet","01.csharp\u002F09.ado-net\u002F01.introduction-to-adonet",{"title":414,"path":415,"stem":416},"9.2. Клас DbConnection — з'єднання з базою даних","\u002Fcsharp\u002Fado-net\u002Fconnection","01.csharp\u002F09.ado-net\u002F02.connection",{"title":418,"path":419,"stem":420},"9.3. Клас DbCommand — виконання SQL-запитів","\u002Fcsharp\u002Fado-net\u002Fcommand-and-queries","01.csharp\u002F09.ado-net\u002F03.command-and-queries",{"title":422,"path":423,"stem":424},"9.4. Клас DbDataReader — ефективне читання даних","\u002Fcsharp\u002Fado-net\u002Fdatareader","01.csharp\u002F09.ado-net\u002F04.datareader",{"title":426,"path":427,"stem":428},"9.5. Параметризовані запити та захист від SQL Injection","\u002Fcsharp\u002Fado-net\u002Fparameters-and-sql-injection","01.csharp\u002F09.ado-net\u002F05.parameters-and-sql-injection",{"title":430,"path":431,"stem":432},"9.6. Транзакції в ADO.NET","\u002Fcsharp\u002Fado-net\u002Ftransactions","01.csharp\u002F09.ado-net\u002F06.transactions",{"title":434,"path":435,"stem":436},"9.7. DbProviderFactory — провайдер-незалежний код","\u002Fcsharp\u002Fado-net\u002Fprovider-factory","01.csharp\u002F09.ado-net\u002F07.provider-factory",{"title":438,"path":439,"stem":440},"9.8. Асинхронний доступ до даних","\u002Fcsharp\u002Fado-net\u002Fasync-data-access","01.csharp\u002F09.ado-net\u002F08.async-data-access",{"title":442,"path":443,"stem":444},"9.9. Від'єднаний режим: DataSet, DataTable, DataRow","\u002Fcsharp\u002Fado-net\u002Fdisconnected-mode-dataset","01.csharp\u002F09.ado-net\u002F09.disconnected-mode-dataset",{"title":446,"path":447,"stem":448},"9.10. DataAdapter — міст між DataSet та базою даних","\u002Fcsharp\u002Fado-net\u002Fdata-adapter","01.csharp\u002F09.ado-net\u002F10.data-adapter",{"title":450,"path":451,"stem":452},"9.11. Data Mapper та Repository: Архітектура доступу до даних","\u002Fcsharp\u002Fado-net\u002Fdata-mapper-repository","01.csharp\u002F09.ado-net\u002F11.data-mapper-repository",{"title":454,"path":455,"stem":456},"9.12. Identity Map, Unit of Work та Specification Pattern","\u002Fcsharp\u002Fado-net\u002Fadvanced-patterns","01.csharp\u002F09.ado-net\u002F12.advanced-patterns",{"title":458,"icon":255,"path":459,"stem":460,"children":461,"page":59},"Ef Core","\u002Fcsharp\u002Fef-core","01.csharp\u002F10.ef-core",[462,466,470,474,478,482,486,490,494,498,502,506,510,514,518,522,526,532,538,542,546,550,554,558,562,566,570,574,578,582,586,590,594,598,602,606,610,614,618,622,626,630,634,638,642,646],{"title":463,"path":464,"stem":465},"Що таке ORM? Від SQL до об'єктів","\u002Fcsharp\u002Fef-core\u002Fwhat-is-orm","01.csharp\u002F10.ef-core\u002F01.what-is-orm",{"title":467,"path":468,"stem":469},"Перший проєкт — від нуля до CRUD","\u002Fcsharp\u002Fef-core\u002Ffirst-project","01.csharp\u002F10.ef-core\u002F02.first-project",{"title":471,"path":472,"stem":473},"DbContext — Серце EF Core","\u002Fcsharp\u002Fef-core\u002Fdbcontext-deep-dive","01.csharp\u002F10.ef-core\u002F03.dbcontext-deep-dive",{"title":475,"path":476,"stem":477},"Провайдери баз даних — Архітектура та Вибір СУБД","\u002Fcsharp\u002Fef-core\u002Fdatabase-providers","01.csharp\u002F10.ef-core\u002F04.database-providers",{"title":479,"path":480,"stem":481},"Конвенції EF Core — Магія без конфігурації","\u002Fcsharp\u002Fef-core\u002Fconventions","01.csharp\u002F10.ef-core\u002F05.conventions",{"title":483,"path":484,"stem":485},"Fluent API та Data Annotations — Явна конфігурація моделі","\u002Fcsharp\u002Fef-core\u002Ffluent-api-vs-annotations","01.csharp\u002F10.ef-core\u002F06.fluent-api-vs-annotations",{"title":487,"path":488,"stem":489},"Зв'язки — One-to-One та One-to-Many","\u002Fcsharp\u002Fef-core\u002Frelationships-basics","01.csharp\u002F10.ef-core\u002F07.relationships-basics",{"title":491,"path":492,"stem":493},"Зв'язки Advanced — Many-to-Many та Складні Сценарії","\u002Fcsharp\u002Fef-core\u002Frelationships-advanced","01.csharp\u002F10.ef-core\u002F08.relationships-advanced",{"title":495,"path":496,"stem":497},"Властивості — Типи, Конвертери, Компаратори (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fproperty-configuration-part1","01.csharp\u002F10.ef-core\u002F09.property-configuration-part1",{"title":499,"path":500,"stem":501},"Властивості — Value Comparers, Generators, Shadow Properties (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fproperty-configuration-part2","01.csharp\u002F10.ef-core\u002F09.property-configuration-part2",{"title":503,"path":504,"stem":505},"Складні типи — Owned Types та Complex Types (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fcomplex-types-owned-part1","01.csharp\u002F10.ef-core\u002F10.complex-types-owned-part1",{"title":507,"path":508,"stem":509},"Складні типи — Complex Types, Keyless Entities, Порівняння (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fcomplex-types-owned-part2","01.csharp\u002F10.ef-core\u002F10.complex-types-owned-part2",{"title":511,"path":512,"stem":513},"JSON Columns — Складні дані у JSON (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fjson-columns-part1","01.csharp\u002F10.ef-core\u002F11.json-columns-part1",{"title":515,"path":516,"stem":517},"JSON Columns — Value Comparers, Індекси, Провайдери (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fjson-columns-part2","01.csharp\u002F10.ef-core\u002F11.json-columns-part2",{"title":519,"path":520,"stem":521},"Успадкування — Абстрактні класи та TPH (Частина 1)","\u002Fcsharp\u002Fef-core\u002Finheritance-part1","01.csharp\u002F10.ef-core\u002F12.inheritance-part1",{"title":523,"path":524,"stem":525},"Успадкування — TPT, TPC та Порівняння Стратегій (Частина 2)","\u002Fcsharp\u002Fef-core\u002Finheritance-part2","01.csharp\u002F10.ef-core\u002F12.inheritance-part2",{"title":527,"path":528,"stem":529,"children":530},"Індекси, Обмеження та Схема (Частина 1)","\u002Fcsharp\u002Fef-core\u002Findexes-constraints-part1","01.csharp\u002F10.ef-core\u002F13.indexes-constraints-part1",[531],{"title":527,"path":528,"stem":529},{"title":533,"path":534,"stem":535,"children":536},"Індекси, Обмеження та Схема (Частина 2)","\u002Fcsharp\u002Fef-core\u002Findexes-constraints-part2","01.csharp\u002F10.ef-core\u002F13.indexes-constraints-part2",[537],{"title":533,"path":534,"stem":535},{"title":539,"path":540,"stem":541},"Seed Data — Початкові Дані (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fseeding-part1","01.csharp\u002F10.ef-core\u002F14.seeding-part1",{"title":543,"path":544,"stem":545},"Seed Data — SQL-скрипти, Bogus та Стратегії (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fseeding-part2","01.csharp\u002F10.ef-core\u002F14.seeding-part2",{"title":547,"path":548,"stem":549},"Global Query Filters — Глобальні Фільтри (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fglobal-query-filters-part1","01.csharp\u002F10.ef-core\u002F15.global-query-filters-part1",{"title":551,"path":552,"stem":553},"Global Query Filters — Підводні камені та Інтеграція (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fglobal-query-filters-part2","01.csharp\u002F10.ef-core\u002F15.global-query-filters-part2",{"title":555,"path":556,"stem":557},"LINQ-запити в EF Core (Частина 1)","\u002Fcsharp\u002Fef-core\u002Flinq-queries-part1","01.csharp\u002F10.ef-core\u002F16.linq-queries-part1",{"title":559,"path":560,"stem":561},"LINQ-запити в EF Core (Частина 2)","\u002Fcsharp\u002Fef-core\u002Flinq-queries-part2","01.csharp\u002F10.ef-core\u002F16.linq-queries-part2",{"title":563,"path":564,"stem":565},"Завантаження Пов'язаних Даних (Частина 1)","\u002Fcsharp\u002Fef-core\u002Floading-related-data-part1","01.csharp\u002F10.ef-core\u002F17.loading-related-data-part1",{"title":567,"path":568,"stem":569},"Завантаження Пов'язаних Даних (Частина 2)","\u002Fcsharp\u002Fef-core\u002Floading-related-data-part2","01.csharp\u002F10.ef-core\u002F17.loading-related-data-part2",{"title":571,"path":572,"stem":573},"Raw SQL, Views та Stored Procedures (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fraw-sql-part1","01.csharp\u002F10.ef-core\u002F18.raw-sql-part1",{"title":575,"path":576,"stem":577},"Raw SQL — Stored Procedures, DbFunction та Bulk Operations (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fraw-sql-part2","01.csharp\u002F10.ef-core\u002F18.raw-sql-part2",{"title":579,"path":580,"stem":581},"Продвинуті Запити — Compiled Queries, Bulk та Оптимізація (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fadvanced-queries-part1","01.csharp\u002F10.ef-core\u002F19.advanced-queries-part1",{"title":583,"path":584,"stem":585},"Продвинуті Запити — Query Tags, Bulk та Interceptors (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fadvanced-queries-part2","01.csharp\u002F10.ef-core\u002F19.advanced-queries-part2",{"title":587,"path":588,"stem":589},"Change Tracker — Відстеження Змін (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fchange-tracking-part1","01.csharp\u002F10.ef-core\u002F20.change-tracking-part1",{"title":591,"path":592,"stem":593},"Change Tracker — Графи Об'єктів та Disconnected (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fchange-tracking-part2","01.csharp\u002F10.ef-core\u002F20.change-tracking-part2",{"title":595,"path":596,"stem":597},"Збереження Даних та Транзакції (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fsaving-data-part1","01.csharp\u002F10.ef-core\u002F21.saving-data-part1",{"title":599,"path":600,"stem":601},"Збереження Даних — Concurrency та Outbox (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fsaving-data-part2","01.csharp\u002F10.ef-core\u002F21.saving-data-part2",{"title":603,"path":604,"stem":605},"Конкурентність та Блокування (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fconcurrency-part1","01.csharp\u002F10.ef-core\u002F22.concurrency-part1",{"title":607,"path":608,"stem":609},"Конкурентність — Дедлоки та Queue Processing (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fconcurrency-part2","01.csharp\u002F10.ef-core\u002F22.concurrency-part2",{"title":611,"path":612,"stem":613},"Міграції в EF Core — Основи (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fmigrations-basics-part1","01.csharp\u002F10.ef-core\u002F23.migrations-basics-part1",{"title":615,"path":616,"stem":617},"Міграції в EF Core — Основи (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fmigrations-basics-part2","01.csharp\u002F10.ef-core\u002F23.migrations-basics-part2",{"title":619,"path":620,"stem":621},"Міграції — Просунуті Сценарії (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fmigrations-advanced-part1","01.csharp\u002F10.ef-core\u002F24.migrations-advanced-part1",{"title":623,"path":624,"stem":625},"Міграції — Просунуті Сценарії (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fmigrations-advanced-part2","01.csharp\u002F10.ef-core\u002F24.migrations-advanced-part2",{"title":627,"path":628,"stem":629},"Управління Схемою та Database-First (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fschema-management-part1","01.csharp\u002F10.ef-core\u002F25.schema-management-part1",{"title":631,"path":632,"stem":633},"Управління Схемою та Database-First (Частина 2)","\u002Fcsharp\u002Fef-core\u002Fschema-management-part2","01.csharp\u002F10.ef-core\u002F25.schema-management-part2",{"title":635,"path":636,"stem":637},"Продуктивність EF Core — Основи (Частина 1)","\u002Fcsharp\u002Fef-core\u002Fperformance-fundamentals-part1","01.csharp\u002F10.ef-core\u002F26.performance-fundamentals-part1",{"title":639,"path":640,"stem":641},"Interceptors в EF Core (Частина 1)","\u002Fcsharp\u002Fef-core\u002Finterceptors-part1","01.csharp\u002F10.ef-core\u002F29.interceptors-part1",{"title":643,"path":644,"stem":645},"Interceptors в EF Core — Connection, Transaction та Materialization (Частина 2)","\u002Fcsharp\u002Fef-core\u002Finterceptors-part2","01.csharp\u002F10.ef-core\u002F29.interceptors-part2",{"title":647,"path":648,"stem":649},"План вивчення Entity Framework Core — Повний курс","\u002Fcsharp\u002Fef-core\u002Fimplementation_plan","01.csharp\u002F10.ef-core\u002Fimplementation_plan",{"title":651,"icon":652,"path":653,"stem":654,"children":655,"page":59},"ASP.NET","i-devicon-dotnetcore","\u002Fcsharp\u002Faspnet","01.csharp\u002F11.aspnet",[656,730,791,869,927,941,967,1057,1111,1182,1212,1289,1346],{"title":657,"icon":658,"path":659,"stem":660,"children":661,"page":59},"Minimal API","i-lucide-network","\u002Fcsharp\u002Faspnet\u002Fminimal-api","01.csharp\u002F11.aspnet\u002F01.minimal-api",[662,666,670,674,678,682,686,690,694,698,702,706,710,714,718,722,726],{"title":663,"path":664,"stem":665},"Вступ до ASP.NET та еволюція фреймворку","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fintroduction","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F01.introduction",{"title":667,"path":668,"stem":669},"Перший додаток на ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Ffirst-application","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F02.first-application",{"title":671,"path":672,"stem":673},"WebApplication, Builder та Dependency Injection","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fwebapplication-builder","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F03.webapplication-builder",{"title":675,"path":676,"stem":677},"Конвеєр запитів та Middleware","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Frequest-pipeline-middleware","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F04.request-pipeline-middleware",{"title":679,"path":680,"stem":681},"Маршрутизація в ASP.NET Core: Основи","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Frouting-basics","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F05.routing-basics",{"title":683,"path":684,"stem":685},"Маршрутизація в ASP.NET Core: Розширені можливості","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Frouting-advanced","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F06.routing-advanced",{"title":687,"path":688,"stem":689},"Статичні файли в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fstatic-files","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F07.static-files",{"title":691,"path":692,"stem":693},"Статичні Активи: MapStaticAssets (ASP.NET Core 9.0)","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fstatic-assets","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F08.static-assets",{"title":695,"path":696,"stem":697},"Конфігурація в ASP.NET Core: Основи","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fconfiguration-fundamentals","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F09.configuration-fundamentals",{"title":699,"path":700,"stem":701},"Конфігурація: Паттерн Options","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fconfiguration-options","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F10.configuration-options",{"title":703,"path":704,"stem":705},"Логування в ASP.NET Core: Основи","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Flogging-basics","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F11.logging-basics",{"title":707,"path":708,"stem":709},"Логування: Serilog та Middleware","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Flogging-advanced","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F12.logging-advanced",{"title":711,"path":712,"stem":713},"Управління станом: HttpContext.Items та Cookies","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fstate-management","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F13.state-management",{"title":715,"path":716,"stem":717},"Стан сесії: Sessions","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fsession-state","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F14.session-state",{"title":719,"path":720,"stem":721},"Структура проєкту: від хаосу до архітектури","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fproject-structure","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F15.project-structure",{"title":723,"path":724,"stem":725},"Scalar у Minimal API: повний проєкт і Fluent OpenAPI","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fscalar-openapi-fluent","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F16.scalar-openapi-fluent",{"title":727,"path":728,"stem":729},"Swagger \u002F Swashbuckle у Minimal API: окремий класичний шлях","\u002Fcsharp\u002Faspnet\u002Fminimal-api\u002Fswagger-swashbuckle","01.csharp\u002F11.aspnet\u002F01.minimal-api\u002F17.swagger-swashbuckle",{"title":731,"icon":658,"path":732,"stem":733,"children":734,"page":59},"API","\u002Fcsharp\u002Faspnet\u002Fapi","01.csharp\u002F11.aspnet\u002F02.api",[735,739,743,747,751,755,759,763,767,771,775,779,783,787],{"title":736,"path":737,"stem":738},"Що таке API. Клієнт-серверна архітектура","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fwhat-is-api","01.csharp\u002F11.aspnet\u002F02.api\u002F01.what-is-api",{"title":740,"path":741,"stem":742},"Формати даних: JSON, XML, TOML та бінарні формати","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fdata-formats","01.csharp\u002F11.aspnet\u002F02.api\u002F02.data-formats",{"title":744,"path":745,"stem":746},"Парадигми API та концепція REST","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-paradigms-rest","01.csharp\u002F11.aspnet\u002F02.api\u002F03.api-paradigms-rest",{"title":748,"path":749,"stem":750},"HTTP-методи, статус-коди та заголовки","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fhttp-methods-status-codes","01.csharp\u002F11.aspnet\u002F02.api\u002F04.http-methods-status-codes",{"title":752,"path":753,"stem":754},"Організація HTTP API за принципами REST","\u002Fcsharp\u002Faspnet\u002Fapi\u002Frest-organizing","01.csharp\u002F11.aspnet\u002F02.api\u002F05.rest-organizing",{"title":756,"path":757,"stem":758},"Номенклатура URL та CRUD-операції","\u002Fcsharp\u002Faspnet\u002Fapi\u002Furl-nomenclature-crud","01.csharp\u002F11.aspnet\u002F02.api\u002F06.url-nomenclature-crud",{"title":760,"path":761,"stem":762},"Правила дизайну: іменування та стандарти","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-design-naming","01.csharp\u002F11.aspnet\u002F02.api\u002F07.api-design-naming",{"title":764,"path":765,"stem":766},"Валідація, ліміти та обробка помилок","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-design-validation","01.csharp\u002F11.aspnet\u002F02.api\u002F08.api-design-validation",{"title":768,"path":769,"stem":770},"Обробка помилок у Minimal API","\u002Fcsharp\u002Faspnet\u002Fapi\u002Ferror-handling-http","01.csharp\u002F11.aspnet\u002F02.api\u002F09.error-handling-http",{"title":772,"path":773,"stem":774},"Ідемпотентність та синхронізація стану","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fidempotency-sync","01.csharp\u002F11.aspnet\u002F02.api\u002F10.idempotency-sync",{"title":776,"path":777,"stem":778},"Пагінація та організація списків","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fpagination-lists","01.csharp\u002F11.aspnet\u002F02.api\u002F11.pagination-lists",{"title":780,"path":781,"stem":782},"Безпека API, кешування та інтернаціоналізація","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fsecurity-auth","01.csharp\u002F11.aspnet\u002F02.api\u002F12.security-auth",{"title":784,"path":785,"stem":786},"Процес проєктування API та документування","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fapi-design-process","01.csharp\u002F11.aspnet\u002F02.api\u002F13.api-design-process",{"title":788,"path":789,"stem":790},"OpenAPI: контракт, специфікація та документація API","\u002Fcsharp\u002Faspnet\u002Fapi\u002Fopenapi","01.csharp\u002F11.aspnet\u002F02.api\u002F14.openapi",{"title":792,"icon":793,"path":794,"stem":795,"children":796,"page":59},"Auth","i-lucide-shield-check","\u002Fcsharp\u002Faspnet\u002Fauth","01.csharp\u002F11.aspnet\u002F03.auth",[797,801,805,809,813,817,821,825,829,833,837,841,845,849,853,857,861,865],{"title":798,"path":799,"stem":800},"Основи аутентифікації та авторизації","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fauth-fundamentals","01.csharp\u002F11.aspnet\u002F03.auth\u002F01.auth-fundamentals",{"title":802,"path":803,"stem":804},"JWT-аутентифікація","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fjwt-authentication","01.csharp\u002F11.aspnet\u002F03.auth\u002F02.jwt-authentication",{"title":806,"path":807,"stem":808},"Авторизація: ролі, політики та resource-based доступ","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fauthorization-policies","01.csharp\u002F11.aspnet\u002F03.auth\u002F03.authorization-policies",{"title":810,"path":811,"stem":812},"Cookie-аутентифікація та ASP.NET Core Identity","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fcookie-auth-identity","01.csharp\u002F11.aspnet\u002F03.auth\u002F04.cookie-auth-identity",{"title":814,"path":815,"stem":816},"JWT + Refresh Tokens (HttpOnly Cookie)","\u002Fcsharp\u002Faspnet\u002Fauth\u002F04b.identity-auth-jwt","01.csharp\u002F11.aspnet\u002F03.auth\u002F04b.identity-auth-jwt",{"title":818,"path":819,"stem":820},"Identity: Підтвердження Email та Скидання Пароля","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fidentity-email-confirmation","01.csharp\u002F11.aspnet\u002F03.auth\u002F05.identity-email-confirmation",{"title":822,"path":823,"stem":824},"Identity: Двофакторна Аутентифікація (2FA)","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fidentity-two-factor","01.csharp\u002F11.aspnet\u002F03.auth\u002F06.identity-two-factor",{"title":826,"path":827,"stem":828},"Identity: Внутрішня Архітектура та Кастомізація","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fidentity-internals","01.csharp\u002F11.aspnet\u002F03.auth\u002F07.identity-internals",{"title":830,"path":831,"stem":832},"OAuth 2.0 та зовнішні провайдери","\u002Fcsharp\u002Faspnet\u002Fauth\u002Foauth-external-providers","01.csharp\u002F11.aspnet\u002F03.auth\u002F08.oauth-external-providers",{"title":834,"path":835,"stem":836},"Безпека на практиці: CORS, HTTPS та захист від атак","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fsecurity-hardening","01.csharp\u002F11.aspnet\u002F03.auth\u002F09.security-hardening",{"title":838,"path":839,"stem":840},"Теорія OAuth 2.0: Поняття, Аналогії та Флоу","\u002Fcsharp\u002Faspnet\u002Fauth\u002Foauth-theory","01.csharp\u002F11.aspnet\u002F03.auth\u002F10.oauth-theory",{"title":842,"path":843,"stem":844},"OIDC, OAuth 2.0 та Keycloak в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Foidc-keycloak","01.csharp\u002F11.aspnet\u002F03.auth\u002F10.oidc-keycloak",{"title":846,"path":847,"stem":848},"API Keys аутентифікація в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fapi-keys","01.csharp\u002F11.aspnet\u002F03.auth\u002F11.api-keys",{"title":850,"path":851,"stem":852},"Rate Limiting та Throttling в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Frate-limiting","01.csharp\u002F11.aspnet\u002F03.auth\u002F12.rate-limiting",{"title":854,"path":855,"stem":856},"Refresh Token Rotation в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Frefresh-token-rotation","01.csharp\u002F11.aspnet\u002F03.auth\u002F13.refresh-token-rotation",{"title":858,"path":859,"stem":860},"Certificate Authentication та mTLS в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fcertificate-auth","01.csharp\u002F11.aspnet\u002F03.auth\u002F14.certificate-auth",{"title":862,"path":863,"stem":864},"RBAC, ABAC та ReBAC в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Frbac-abac-rebac","01.csharp\u002F11.aspnet\u002F03.auth\u002F15.rbac-abac-rebac",{"title":866,"path":867,"stem":868},"Multi-tenancy та ізоляція даних в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fauth\u002Fmulti-tenancy","01.csharp\u002F11.aspnet\u002F03.auth\u002F16.multi-tenancy",{"title":870,"icon":871,"path":872,"stem":873,"children":874,"page":59},"Нотифікації","i-lucide-bell","\u002Fcsharp\u002Faspnet\u002Fnotifications","01.csharp\u002F11.aspnet\u002F04.notifications",[875,879,883,887,891,895,899,903,907,911,915,919,923],{"title":876,"path":877,"stem":878},"In-App нотифікації через базу даних","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fin-app-database-notifications","01.csharp\u002F11.aspnet\u002F04.notifications\u002F01.in-app-database-notifications",{"title":880,"path":881,"stem":882},"Polling: Регулярний запит оновлень","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fpolling","01.csharp\u002F11.aspnet\u002F04.notifications\u002F02.polling",{"title":884,"path":885,"stem":886},"Server-Sent Events: Однострімовий push від сервера","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fserver-sent-events","01.csharp\u002F11.aspnet\u002F04.notifications\u002F03.server-sent-events",{"title":888,"path":889,"stem":890},"WebSockets: Двостороннє з'єднання в реальному часі","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fwebsockets","01.csharp\u002F11.aspnet\u002F04.notifications\u002F04.websockets",{"title":892,"path":893,"stem":894},"SignalR: Абстракція над транспортами реального часу","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fsignalr","01.csharp\u002F11.aspnet\u002F04.notifications\u002F05.signalr",{"title":896,"path":897,"stem":898},"Background Services: Фонові задачі в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fbackground-services","01.csharp\u002F11.aspnet\u002F04.notifications\u002F06.background-services",{"title":900,"path":901,"stem":902},"Web Push нотифікації","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fweb-push","01.csharp\u002F11.aspnet\u002F04.notifications\u002F07.web-push",{"title":904,"path":905,"stem":906},"Email нотифікації","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Femail-notifications","01.csharp\u002F11.aspnet\u002F04.notifications\u002F08.email-notifications",{"title":908,"path":909,"stem":910},"Порівняння підходів: Як вибрати правильну технологію нотифікацій","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fchoosing-the-right-approach","01.csharp\u002F11.aspnet\u002F04.notifications\u002F09.choosing-the-right-approach",{"title":912,"path":913,"stem":914},"Hangfire: Надійне планування фонових задач","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fhangfire","01.csharp\u002F11.aspnet\u002F04.notifications\u002F10.hangfire",{"title":916,"path":917,"stem":918},"Практика: Конвертація зображень у WebP через Hangfire","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fhangfire-image-webp","01.csharp\u002F11.aspnet\u002F04.notifications\u002F11.hangfire-image-webp",{"title":920,"path":921,"stem":922},"Практика: Підготовка відео до HLS-стрімінгу через Hangfire","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Fhangfire-video-hls","01.csharp\u002F11.aspnet\u002F04.notifications\u002F12.hangfire-video-hls",{"title":924,"path":925,"stem":926},"Telegram-нотифікації: від одного повідомлення до масових розсилок і мульти-канального підходу","\u002Fcsharp\u002Faspnet\u002Fnotifications\u002Ftelegram-notifications","01.csharp\u002F11.aspnet\u002F04.notifications\u002F13.telegram-notifications",{"title":928,"icon":929,"path":930,"stem":931,"children":932,"page":59},"Інтернаціоналізація","i-lucide-languages","\u002Fcsharp\u002Faspnet\u002Fi18n","01.csharp\u002F11.aspnet\u002F05.i18n",[933,937],{"title":934,"path":935,"stem":936},"Інтернаціоналізація (i18n) у Minimal API: від A до Я","\u002Fcsharp\u002Faspnet\u002Fi18n\u002Finternationalization","01.csharp\u002F11.aspnet\u002F05.i18n\u002F01.internationalization",{"title":938,"path":939,"stem":940},"Humanizer: людиномовні рядки у .NET","\u002Fcsharp\u002Faspnet\u002Fi18n\u002Fhumanizer","01.csharp\u002F11.aspnet\u002F05.i18n\u002F02.humanizer",{"title":942,"icon":943,"path":944,"stem":945,"children":946,"page":59},"Кешування","i-lucide-layers","\u002Fcsharp\u002Faspnet\u002Fcaching","01.csharp\u002F11.aspnet\u002F06.caching",[947,951,955,959,963],{"title":948,"path":949,"stem":950},"Огляд кешування: чотири рівні і коли що обирати","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fcaching","01.csharp\u002F11.aspnet\u002F06.caching\u002F01.caching",{"title":952,"path":953,"stem":954},"IMemoryCache: кеш в оперативній пам'яті","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fmemory-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F02.memory-cache",{"title":956,"path":957,"stem":958},"IDistributedCache і Redis: розподілений кеш","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fdistributed-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F03.distributed-cache",{"title":960,"path":961,"stem":962},"Response Cache: HTTP-кешування через Cache-Control","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Fresponse-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F04.response-cache",{"title":964,"path":965,"stem":966},"Output Cache: серверний кеш HTTP-відповідей (.NET 7+)","\u002Fcsharp\u002Faspnet\u002Fcaching\u002Foutput-cache","01.csharp\u002F11.aspnet\u002F06.caching\u002F05.output-cache",{"title":968,"icon":969,"path":970,"stem":971,"children":972,"page":59},"Тестування","i-lucide-test-tube","\u002Fcsharp\u002Faspnet\u002Ftesting","01.csharp\u002F11.aspnet\u002F07.testing",[973,977,981,985,989,993,997,1001,1005,1009,1013,1017,1021,1025,1029,1033,1037,1041,1045,1049,1053],{"title":974,"path":975,"stem":976},"Що таке тестування? Від інтуїції до науки","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fwhat-is-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F01.what-is-testing",{"title":978,"path":979,"stem":980},"Піраміда тестування — Стратегія, а не Догма","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftesting-pyramid","01.csharp\u002F11.aspnet\u002F07.testing\u002F02.testing-pyramid",{"title":982,"path":983,"stem":984},"Дві Школи Тестування — Лондон проти Детройту","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftesting-schools","01.csharp\u002F11.aspnet\u002F07.testing\u002F03.testing-schools",{"title":986,"path":987,"stem":988},"TDD та BDD — Тести як Дизайн-інструмент","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftdd-and-bdd","01.csharp\u002F11.aspnet\u002F07.testing\u002F04.tdd-and-bdd",{"title":990,"path":991,"stem":992},"Що саме тестувати — Техніки аналізу та Циклomatична складність","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fwhat-to-test","01.csharp\u002F11.aspnet\u002F07.testing\u002F05.what-to-test",{"title":994,"path":995,"stem":996},"Тестові Фреймворки — Навіщо вони і що всередині","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftest-frameworks","01.csharp\u002F11.aspnet\u002F07.testing\u002F06.test-frameworks",{"title":998,"path":999,"stem":1000},"xUnit — Факти, Теорії та Lifecycle тестів","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fxunit-basics","01.csharp\u002F11.aspnet\u002F07.testing\u002F07.xunit-basics",{"title":1002,"path":1003,"stem":1004},"xUnit Advanced — Fixtures, Кастомізація та Розширення","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fxunit-advanced","01.csharp\u002F11.aspnet\u002F07.testing\u002F08.xunit-advanced",{"title":1006,"path":1007,"stem":1008},"Moq — Глибоке занурення в мокування","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fmocking-with-moq","01.csharp\u002F11.aspnet\u002F07.testing\u002F09.mocking-with-moq",{"title":1010,"path":1011,"stem":1012},"Тестування Баз Даних — EF Core, SQLite та Testcontainers","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fdatabase-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F10.database-testing",{"title":1014,"path":1015,"stem":1016},"Integration Testing — Частина 1 [Теорія та WebApplicationFactory]","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fintegration-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F11.integration-testing",{"title":1018,"path":1019,"stem":1020},"Інтеграційне тестування — Практика","\u002Fcsharp\u002Faspnet\u002Ftesting\u002F11a.integration-testing-practice","01.csharp\u002F11.aspnet\u002F07.testing\u002F11a.integration-testing-practice",{"title":1022,"path":1023,"stem":1024},"Integration Testing — Частина 2 [Просунуті Сценарії та Testcontainers]","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fintegration-testing-advanced","01.csharp\u002F11.aspnet\u002F07.testing\u002F12.integration-testing-advanced",{"title":1026,"path":1027,"stem":1028},"Професійний Postman: Колекції, Змінні та GitHub Інтеграція","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fpostman-professional","01.csharp\u002F11.aspnet\u002F07.testing\u002F13.postman-professional",{"title":1030,"path":1031,"stem":1032},"HttpClient у Тестах Частина 1: Архітектура та MockHttpMessageHandler","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fhttpclient-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F14.httpclient-testing",{"title":1034,"path":1035,"stem":1036},"HttpClient у Тестах Частина 2: WireMock.Net та Resilience","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fwiremock-net","01.csharp\u002F11.aspnet\u002F07.testing\u002F15.wiremock-net",{"title":1038,"path":1039,"stem":1040},"Патерни та Анти-патерни Тестування: Test Smells","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Ftesting-patterns","01.csharp\u002F11.aspnet\u002F07.testing\u002F16.testing-patterns",{"title":1042,"path":1043,"stem":1044},"Просунуті інструменти: Time, Snapshots та Властивості","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fadvanced-testing-tools","01.csharp\u002F11.aspnet\u002F07.testing\u002F17.advanced-testing-tools",{"title":1046,"path":1047,"stem":1048},"Тестування Архітектури з NetArchTest","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Farchitecture-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F18.architecture-testing",{"title":1050,"path":1051,"stem":1052},"Тестування Продуктивності: BenchmarkDotNet, NBomber та k6","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fperformance-testing","01.csharp\u002F11.aspnet\u002F07.testing\u002F19.performance-testing",{"title":1054,"path":1055,"stem":1056},"Залишок плану для курсу \"Тестування ASP.NET Minimal API\"","\u002Fcsharp\u002Faspnet\u002Ftesting\u002Fremaining_plan","01.csharp\u002F11.aspnet\u002F07.testing\u002Fremaining_plan",{"title":1058,"icon":1059,"path":1060,"stem":1061,"children":1062,"page":59},"Платежі","i-lucide-credit-card","\u002Fcsharp\u002Faspnet\u002Fpayments","01.csharp\u002F11.aspnet\u002F08.payments",[1063,1067,1071,1075,1079,1083,1087,1091,1095,1099,1103,1107],{"title":1064,"path":1065,"stem":1066},"Основи платіжної інфраструктури","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpayment-fundamentals","01.csharp\u002F11.aspnet\u002F08.payments\u002F01.payment-fundamentals",{"title":1068,"path":1069,"stem":1070},"Методи оплати в Україні","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpayment-methods-ukraine","01.csharp\u002F11.aspnet\u002F08.payments\u002F02.payment-methods-ukraine",{"title":1072,"path":1073,"stem":1074},"PCI DSS та безпека платежів","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpci-dss-security","01.csharp\u002F11.aspnet\u002F08.payments\u002F03.pci-dss-security",{"title":1076,"path":1077,"stem":1078},"Архітектура платіжної підсистеми","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fpayment-architecture","01.csharp\u002F11.aspnet\u002F08.payments\u002F04.payment-architecture",{"title":1080,"path":1081,"stem":1082},"Інтеграція LiqPay (ПриватБанк)","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fliqpay-integration","01.csharp\u002F11.aspnet\u002F08.payments\u002F05.liqpay-integration",{"title":1084,"path":1085,"stem":1086},"Інтеграція Monobank Acquiring API","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fmonobank-acquiring","01.csharp\u002F11.aspnet\u002F08.payments\u002F06.monobank-acquiring",{"title":1088,"path":1089,"stem":1090},"Інтеграція Stripe","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fstripe-integration","01.csharp\u002F11.aspnet\u002F08.payments\u002F07.stripe-integration",{"title":1092,"path":1093,"stem":1094},"Webhooks — глибоке занурення","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fwebhooks-deep-dive","01.csharp\u002F11.aspnet\u002F08.payments\u002F08.webhooks-deep-dive",{"title":1096,"path":1097,"stem":1098},"Підписки та рекурентні платежі","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fsubscriptions-recurring","01.csharp\u002F11.aspnet\u002F08.payments\u002F09.subscriptions-recurring",{"title":1100,"path":1101,"stem":1102},"Повернення коштів та диспути","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Frefunds-disputes","01.csharp\u002F11.aspnet\u002F08.payments\u002F10.refunds-disputes",{"title":1104,"path":1105,"stem":1106},"Тестування платіжних інтеграцій","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Ftesting-payments","01.csharp\u002F11.aspnet\u002F08.payments\u002F11.testing-payments",{"title":1108,"path":1109,"stem":1110},"Чекліст виходу в Production","\u002Fcsharp\u002Faspnet\u002Fpayments\u002Fproduction-checklist","01.csharp\u002F11.aspnet\u002F08.payments\u002F12.production-checklist",{"title":1112,"icon":1113,"items":1114,"path":1127,"stem":1128,"children":1129,"page":59},"Популярні бібліотеки","lucide:box",[1115,1116,1117,1118,1119,1120,1121,1122,1123,1124,1125,1126],"01.fluent-validation","02.mapster","03.erroror-result-pattern","04.serilog","05.mediatr","06.polly","07.health-checks","08.feature-management","09.fluent-email","10.quest-pdf","11.bogus","12.humanizer-guard","\u002Fcsharp\u002Faspnet\u002Flibraries","01.csharp\u002F11.aspnet\u002F09.libraries",[1130,1134,1138,1142,1146,1150,1154,1158,1162,1166,1170,1174,1178],{"title":1131,"path":1132,"stem":1133},"Валідація з FluentValidation в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ffluent-validation","01.csharp\u002F11.aspnet\u002F09.libraries\u002F01.fluent-validation",{"title":1135,"path":1136,"stem":1137},"Маппінг об","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fmapster","01.csharp\u002F11.aspnet\u002F09.libraries\u002F02.mapster",{"title":1139,"path":1140,"stem":1141},"Обробка помилок з ErrorOr та Result Pattern в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ferroror-result-pattern","01.csharp\u002F11.aspnet\u002F09.libraries\u002F03.erroror-result-pattern",{"title":1143,"path":1144,"stem":1145},"Структуроване логування з Serilog в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fserilog","01.csharp\u002F11.aspnet\u002F09.libraries\u002F04.serilog",{"title":1147,"path":1148,"stem":1149},"CQRS та Mediator з MediatR в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fmediatr","01.csharp\u002F11.aspnet\u002F09.libraries\u002F05.mediatr",{"title":1151,"path":1152,"stem":1153},"Відмовостійкість з Polly в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fpolly","01.csharp\u002F11.aspnet\u002F09.libraries\u002F06.polly",{"title":1155,"path":1156,"stem":1157},"Health Checks в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fhealth-checks","01.csharp\u002F11.aspnet\u002F09.libraries\u002F07.health-checks",{"title":1159,"path":1160,"stem":1161},"Feature Management та Feature Flags в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ffeature-management","01.csharp\u002F11.aspnet\u002F09.libraries\u002F08.feature-management",{"title":1163,"path":1164,"stem":1165},"Відправка Email з FluentEmail в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Ffluent-email","01.csharp\u002F11.aspnet\u002F09.libraries\u002F09.fluent-email",{"title":1167,"path":1168,"stem":1169},"Генерація PDF з QuestPDF в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fquest-pdf","01.csharp\u002F11.aspnet\u002F09.libraries\u002F10.quest-pdf",{"title":1171,"path":1172,"stem":1173},"Генерація тестових даних з Bogus в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fbogus","01.csharp\u002F11.aspnet\u002F09.libraries\u002F11.bogus",{"title":1175,"path":1176,"stem":1177},"Humanizer та Guard Clauses в ASP.NET Core","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fhumanizer-guard","01.csharp\u002F11.aspnet\u002F09.libraries\u002F12.humanizer-guard",{"title":1179,"path":1180,"stem":1181},"План модуля 10.libraries — Популярні бібліотеки ASP.NET","\u002Fcsharp\u002Faspnet\u002Flibraries\u002Fplan","01.csharp\u002F11.aspnet\u002F09.libraries\u002Fplan",{"title":1183,"icon":1184,"path":1185,"stem":1186,"children":1187,"page":59},"Razor Pages","i-lucide-layout-template","\u002Fcsharp\u002Faspnet\u002Frazor-pages","01.csharp\u002F11.aspnet\u002F10.razor-pages",[1188,1192,1196,1200,1204,1208],{"title":1189,"path":1190,"stem":1191},"Від Minimal API до Razor Pages: концептуальний перехід","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Ffrom-minimal-api","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F01.from-minimal-api",{"title":1193,"path":1194,"stem":1195},"PageModel: логіка сторінки Razor Pages","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Fpage-model","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F02.page-model",{"title":1197,"path":1198,"stem":1199},"Razor синтаксис: шаблонізатор у .cshtml","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Frazor-syntax","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F03.razor-syntax",{"title":1201,"path":1202,"stem":1203},"Tag Helpers: типізований HTML","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Ftag-helpers","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F04.tag-helpers",{"title":1205,"path":1206,"stem":1207},"Форми і валідація: повний цикл обробки даних","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Fforms-validation","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F05.forms-validation",{"title":1209,"path":1210,"stem":1211},"Практичний проєкт: TaskManager на Razor Pages","\u002Fcsharp\u002Faspnet\u002Frazor-pages\u002Fproject-task-manager","01.csharp\u002F11.aspnet\u002F10.razor-pages\u002F06.project-task-manager",{"title":1213,"path":1214,"stem":1215,"children":1216,"page":59},"ASP.NET Core MVC","\u002Fcsharp\u002Faspnet\u002Fmvc","01.csharp\u002F11.aspnet\u002F11.mvc",[1217,1221,1225,1229,1233,1237,1241,1245,1249,1253,1257,1261,1265,1269,1273,1277,1281,1285],{"title":1218,"path":1219,"stem":1220},"Патерн MVC: архітектура, що змінила веб","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fmvc-pattern","01.csharp\u002F11.aspnet\u002F11.mvc\u002F01.mvc-pattern",{"title":1222,"path":1223,"stem":1224},"Від Razor Pages до MVC: концептуальний перехід","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Ffrom-razor-pages","01.csharp\u002F11.aspnet\u002F11.mvc\u002F02.from-razor-pages",{"title":1226,"path":1227,"stem":1228},"Controllers та Actions: серце MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fcontrollers-actions","01.csharp\u002F11.aspnet\u002F11.mvc\u002F03.controllers-actions",{"title":1230,"path":1231,"stem":1232},"Маршрутизація в MVC: Convention vs Attribute Routing","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Frouting-mvc","01.csharp\u002F11.aspnet\u002F11.mvc\u002F04.routing-mvc",{"title":1234,"path":1235,"stem":1236},"Model Binding: від HTTP до C#","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fmodel-binding","01.csharp\u002F11.aspnet\u002F11.mvc\u002F05.model-binding",{"title":1238,"path":1239,"stem":1240},"Views, ViewData, ViewBag, TempData і ViewModel","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fviews-viewdata-tempdata","01.csharp\u002F11.aspnet\u002F11.mvc\u002F06.views-viewdata-tempdata",{"title":1242,"path":1243,"stem":1244},"Filters: аспектно-орієнтоване програмування в MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Ffilters","01.csharp\u002F11.aspnet\u002F11.mvc\u002F07.filters",{"title":1246,"path":1247,"stem":1248},"Areas: структурування великих застосунків","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fareas","01.csharp\u002F11.aspnet\u002F11.mvc\u002F08.areas",{"title":1250,"path":1251,"stem":1252},"View Components: повторювані незалежні блоки UI","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fview-components","01.csharp\u002F11.aspnet\u002F11.mvc\u002F09.view-components",{"title":1254,"path":1255,"stem":1256},"Display та Editor Templates","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fdisplay-editor-templates","01.csharp\u002F11.aspnet\u002F11.mvc\u002F10.display-editor-templates",{"title":1258,"path":1259,"stem":1260},"Валідація: IValidatableObject та FluentValidation","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fvalidation-advanced","01.csharp\u002F11.aspnet\u002F11.mvc\u002F11.validation-advanced",{"title":1262,"path":1263,"stem":1264},"HTMX: інтерактивність через HTML-атрибути","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fhtmx","01.csharp\u002F11.aspnet\u002F11.mvc\u002F12.htmx",{"title":1266,"path":1267,"stem":1268},"HTMX у ASP.NET Core MVC: серверна інтеграція","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fajax-htmx-mvc","01.csharp\u002F11.aspnet\u002F11.mvc\u002F13.ajax-htmx-mvc",{"title":1270,"path":1271,"stem":1272},"Практичний проєкт: Каталог товарів з HTMX","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fhtmx-project","01.csharp\u002F11.aspnet\u002F11.mvc\u002F14.htmx-project",{"title":1274,"path":1275,"stem":1276},"Завантаження та обробка файлів","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Ffile-upload","01.csharp\u002F11.aspnet\u002F11.mvc\u002F15.file-upload",{"title":1278,"path":1279,"stem":1280},"Глобалізація та Локалізація MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fglobalization-localization","01.csharp\u002F11.aspnet\u002F11.mvc\u002F16.globalization-localization",{"title":1282,"path":1283,"stem":1284},"Підсумковий проєкт: Блог-платформа","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fmvc-project","01.csharp\u002F11.aspnet\u002F11.mvc\u002F17.mvc-project",{"title":1286,"path":1287,"stem":1288},"План курсу: ASP.NET Core MVC","\u002Fcsharp\u002Faspnet\u002Fmvc\u002Fplan","01.csharp\u002F11.aspnet\u002F11.mvc\u002Fplan",{"title":1290,"path":1291,"stem":1292,"children":1293,"page":59},"Web Api","\u002Fcsharp\u002Faspnet\u002Fweb-api","01.csharp\u002F11.aspnet\u002F12.web-api",[1294,1298,1302,1306,1310,1314,1318,1322,1326,1330,1334,1338,1342],{"title":1295,"path":1296,"stem":1297},"Від Minimal API до Controller-based API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Ffrom-minimal-api-to-controllers","01.csharp\u002F11.aspnet\u002F12.web-api\u002F01.from-minimal-api-to-controllers",{"title":1299,"path":1300,"stem":1301},"ControllerBase, ActionResult\u003CT> та Response Types","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fcontroller-base-actionresult","01.csharp\u002F11.aspnet\u002F12.web-api\u002F02.controller-base-actionresult",{"title":1303,"path":1304,"stem":1305},"Content Negotiation - JSON, XML та власні форматери","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fcontent-negotiation","01.csharp\u002F11.aspnet\u002F12.web-api\u002F03.content-negotiation",{"title":1307,"path":1308,"stem":1309},"Версіонування API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fapi-versioning","01.csharp\u002F11.aspnet\u002F12.web-api\u002F04.api-versioning",{"title":1311,"path":1312,"stem":1313},"ProblemDetails та структурована обробка помилок","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fproblemdetails-error-handling","01.csharp\u002F11.aspnet\u002F12.web-api\u002F05.problemdetails-error-handling",{"title":1315,"path":1316,"stem":1317},"Фільтри у Web API контексті","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Ffilters-for-api","01.csharp\u002F11.aspnet\u002F12.web-api\u002F06.filters-for-api",{"title":1319,"path":1320,"stem":1321},"Пагінація, фільтрація та сортування","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fpagination-filtering-sorting","01.csharp\u002F11.aspnet\u002F12.web-api\u002F07.pagination-filtering-sorting",{"title":1323,"path":1324,"stem":1325},"HATEOAS та Resource Expansion","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fhateoas-resource-expansion","01.csharp\u002F11.aspnet\u002F12.web-api\u002F08.hateoas-resource-expansion",{"title":1327,"path":1328,"stem":1329},"Гібридна архітектура - Minimal API + Controllers","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fminimal-api-vs-controllers-hybrid","01.csharp\u002F11.aspnet\u002F12.web-api\u002F09.minimal-api-vs-controllers-hybrid",{"title":1331,"path":1332,"stem":1333},"Документація API - Swashbuckle, NSwag та генерація клієнтів","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fapi-documentation-generation","01.csharp\u002F11.aspnet\u002F12.web-api\u002F10.api-documentation-generation",{"title":1335,"path":1336,"stem":1337},"Health Checks та моніторинг API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fhealth-checks-monitoring","01.csharp\u002F11.aspnet\u002F12.web-api\u002F11.health-checks-monitoring",{"title":1339,"path":1340,"stem":1341},"Підсумковий проєкт - Production-Ready REST API","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fweb-api-project","01.csharp\u002F11.aspnet\u002F12.web-api\u002F12.web-api-project",{"title":1343,"path":1344,"stem":1345},"План курсу: ASP.NET Core Web API (Controllers)","\u002Fcsharp\u002Faspnet\u002Fweb-api\u002Fplan","01.csharp\u002F11.aspnet\u002F12.web-api\u002Fplan",{"title":1347,"icon":1348,"path":1349,"stem":1350,"children":1351,"page":59},"Моніторинг","i-lucide-activity","\u002Fcsharp\u002Faspnet\u002Fmonitoring","01.csharp\u002F11.aspnet\u002F13.monitoring",[1352,1356,1360],{"title":1353,"path":1354,"stem":1355},"Спостережуваність: від console.log до production-систем","\u002Fcsharp\u002Faspnet\u002Fmonitoring\u002Fobservability-intro","01.csharp\u002F11.aspnet\u002F13.monitoring\u002F01.observability-intro",{"title":1357,"path":1358,"stem":1359},"Health Checks: перший рівень observability","\u002Fcsharp\u002Faspnet\u002Fmonitoring\u002Fhealth-checks","01.csharp\u002F11.aspnet\u002F13.monitoring\u002F02.health-checks",{"title":1361,"path":1362,"stem":1363},"Вбудовані метрики .NET 10 та System.Diagnostics.Metrics","\u002Fcsharp\u002Faspnet\u002Fmonitoring\u002Fdotnet-metrics","01.csharp\u002F11.aspnet\u002F13.monitoring\u002F03.dotnet-metrics",{"title":1365,"icon":1366,"path":1367,"stem":1368,"children":1369,"page":59},"Desktop UI","i-lucide-app-window","\u002Fcsharp\u002Fdesktop-ui","01.csharp\u002F12.desktop-ui",[1370,1374,1378,1382,1386,1390,1394,1398,1402,1406,1410,1414,1418,1422,1426,1430,1434,1438,1442,1446,1450,1454,1458,1462,1466,1470,1474,1478,1482,1486,1490,1494,1498,1502,1506,1510,1514,1518,1522,1526,1530,1534,1538,1542,1546,1550,1554,1558,1562,1566,1570,1574,1578,1582,1586,1590,1594,1598,1602,1606,1610,1614,1618,1622,1626,1630,1634,1638,1642,1646,1650],{"title":1371,"path":1372,"stem":1373},"Що таке десктопна розробка?","\u002Fcsharp\u002Fdesktop-ui\u002Fwhat-is-desktop-dev","01.csharp\u002F12.desktop-ui\u002F01.what-is-desktop-dev",{"title":1375,"path":1376,"stem":1377},"Архітектура WPF — як влаштований графічний інтерфейс","\u002Fcsharp\u002Fdesktop-ui\u002Fwpf-architecture","01.csharp\u002F12.desktop-ui\u002F02.wpf-architecture",{"title":1379,"path":1380,"stem":1381},"Перший WPF-проєкт — від нуля до вікна","\u002Fcsharp\u002Fdesktop-ui\u002Ffirst-wpf-app","01.csharp\u002F12.desktop-ui\u002F03.first-wpf-app",{"title":1383,"path":1384,"stem":1385},"Перший Avalonia-проєкт: WPF для всіх платформ","\u002Fcsharp\u002Fdesktop-ui\u002F03a.first-avalonia-app","01.csharp\u002F12.desktop-ui\u002F03a.first-avalonia-app",{"title":1387,"path":1388,"stem":1389},"XAML: декларативний інтерфейс","\u002Fcsharp\u002Fdesktop-ui\u002Fxaml-basics","01.csharp\u002F12.desktop-ui\u002F04.xaml-basics",{"title":1391,"path":1392,"stem":1393},"Fluent UI у WPF — сучасний дизайн Windows 11","\u002Fcsharp\u002Fdesktop-ui\u002F04a.wpf-fluent-ui","01.csharp\u002F12.desktop-ui\u002F04a.wpf-fluent-ui",{"title":1395,"path":1396,"stem":1397},"WPF UI — сучасна бібліотека Fluent контролів","\u002Fcsharp\u002Fdesktop-ui\u002F04b.wpf-ui-library","01.csharp\u002F12.desktop-ui\u002F04b.wpf-ui-library",{"title":1399,"path":1400,"stem":1401},"HandyControl — велика бібліотека UI контролів для WPF","\u002Fcsharp\u002Fdesktop-ui\u002F04c.handycontrol-library","01.csharp\u002F12.desktop-ui\u002F04c.handycontrol-library",{"title":1403,"path":1404,"stem":1405},"Простори імен та ресурси XAML","\u002Fcsharp\u002Fdesktop-ui\u002Fxaml-namespaces-resources","01.csharp\u002F12.desktop-ui\u002F05.xaml-namespaces-resources",{"title":1407,"path":1408,"stem":1409},"XAML в Avalonia: ключові відмінності від WPF","\u002Fcsharp\u002Fdesktop-ui\u002F05a.avalonia-xaml-differences","01.csharp\u002F12.desktop-ui\u002F05a.avalonia-xaml-differences",{"title":1411,"path":1412,"stem":1413},"Розширення розмітки XAML (Markup Extensions)","\u002Fcsharp\u002Fdesktop-ui\u002Fxaml-markup-extensions","01.csharp\u002F12.desktop-ui\u002F06.xaml-markup-extensions",{"title":1415,"path":1416,"stem":1417},"Панелі Layout: StackPanel, WrapPanel, DockPanel","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-panels-part1","01.csharp\u002F12.desktop-ui\u002F07.layout-panels-part1",{"title":1419,"path":1420,"stem":1421},"Grid, Canvas, UniformGrid","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-panels-part2","01.csharp\u002F12.desktop-ui\u002F07.layout-panels-part2",{"title":1423,"path":1424,"stem":1425},"Просунуті техніки Layout","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-advanced","01.csharp\u002F12.desktop-ui\u002F08.layout-advanced",{"title":1427,"path":1428,"stem":1429},"Адаптивний Layout та найкращі практики","\u002Fcsharp\u002Fdesktop-ui\u002Flayout-responsive","01.csharp\u002F12.desktop-ui\u002F09.layout-responsive",{"title":1431,"path":1432,"stem":1433},"Layout в Avalonia: відмінності та нові можливості","\u002Fcsharp\u002Fdesktop-ui\u002F09a.layout-avalonia","01.csharp\u002F12.desktop-ui\u002F09a.layout-avalonia",{"title":1435,"path":1436,"stem":1437},"Button, Image, ProgressBar та інші базові контроли","\u002Fcsharp\u002Fdesktop-ui\u002Fbasic-controls","01.csharp\u002F12.desktop-ui\u002F10.basic-controls",{"title":1439,"path":1440,"stem":1441},"Контроли в Avalonia: відмінності від WPF","\u002Fcsharp\u002Fdesktop-ui\u002F10a.controls-avalonia","01.csharp\u002F12.desktop-ui\u002F10a.controls-avalonia",{"title":1443,"path":1444,"stem":1445},"Текстові контроли — TextBlock, TextBox, RichTextBox","\u002Fcsharp\u002Fdesktop-ui\u002Ftext-controls","01.csharp\u002F12.desktop-ui\u002F11.text-controls",{"title":1447,"path":1448,"stem":1449},"Контроли вибору — CheckBox, RadioButton, ComboBox, ListBox, DatePicker","\u002Fcsharp\u002Fdesktop-ui\u002Fselection-controls","01.csharp\u002F12.desktop-ui\u002F12.selection-controls",{"title":1451,"path":1452,"stem":1453},"Content Model — GroupBox, Expander, TabControl, StatusBar","\u002Fcsharp\u002Fdesktop-ui\u002Fcontent-controls","01.csharp\u002F12.desktop-ui\u002F13.content-controls",{"title":1455,"path":1456,"stem":1457},"UI\u002FUX принципи десктопних застосунків","\u002Fcsharp\u002Fdesktop-ui\u002F13a.ui-ux-principles","01.csharp\u002F12.desktop-ui\u002F13a.ui-ux-principles",{"title":1459,"path":1460,"stem":1461},"Dependency Properties — Концепція та Value Resolution","\u002Fcsharp\u002Fdesktop-ui\u002Fdependency-properties-part1","01.csharp\u002F12.desktop-ui\u002F14.dependency-properties-part1",{"title":1463,"path":1464,"stem":1465},"Avalonia Property System — StyledProperty та DirectProperty","\u002Fcsharp\u002Fdesktop-ui\u002F14a.avalonia-property-system","01.csharp\u002F12.desktop-ui\u002F14a.avalonia-property-system",{"title":1467,"path":1468,"stem":1469},"Attached Properties — Властивості без меж","\u002Fcsharp\u002Fdesktop-ui\u002Fattached-properties","01.csharp\u002F12.desktop-ui\u002F15.attached-properties",{"title":1471,"path":1472,"stem":1473},"Routed Events — Маршрутизація подій у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Frouted-events","01.csharp\u002F12.desktop-ui\u002F16.routed-events",{"title":1475,"path":1476,"stem":1477},"Data Binding — Від Code-Behind до Декларативності","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-binding-basics-part1","01.csharp\u002F12.desktop-ui\u002F17.data-binding-basics-part1",{"title":1479,"path":1480,"stem":1481},"INotifyPropertyChanged — Живе оновлення UI","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-binding-basics-part2","01.csharp\u002F12.desktop-ui\u002F17.data-binding-basics-part2",{"title":1483,"path":1484,"stem":1485},"Compiled Bindings в Avalonia — Безпека на етапі компіляції","\u002Fcsharp\u002Fdesktop-ui\u002F17a.avalonia-compiled-bindings","01.csharp\u002F12.desktop-ui\u002F17a.avalonia-compiled-bindings",{"title":1487,"path":1488,"stem":1489},"Просунутий Data Binding — ElementName, RelativeSource, MultiBinding","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-binding-advanced","01.csharp\u002F12.desktop-ui\u002F18.data-binding-advanced",{"title":1491,"path":1492,"stem":1493},"Value Converters — Перетворення типів даних у Data Binding","\u002Fcsharp\u002Fdesktop-ui\u002Fvalue-converters","01.csharp\u002F12.desktop-ui\u002F19.value-converters",{"title":1495,"path":1496,"stem":1497},"Data Templates — Візуалізація об'єктів у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-templates","01.csharp\u002F12.desktop-ui\u002F20.data-templates",{"title":1499,"path":1500,"stem":1501},"Collections Binding Part 1 — ObservableCollection та ItemsControl","\u002Fcsharp\u002Fdesktop-ui\u002Fcollections-binding-part1","01.csharp\u002F12.desktop-ui\u002F21.collections-binding-part1",{"title":1503,"path":1504,"stem":1505},"Collections Binding Part 2 — ICollectionView, Filtering, Sorting та Virtualization","\u002Fcsharp\u002Fdesktop-ui\u002Fcollections-binding-part2","01.csharp\u002F12.desktop-ui\u002F21.collections-binding-part2",{"title":1507,"path":1508,"stem":1509},"MVVM Pattern — Від Spaghetti Code до архітектури","\u002Fcsharp\u002Fdesktop-ui\u002Fmvvm-pattern","01.csharp\u002F12.desktop-ui\u002F22.mvvm-pattern",{"title":1511,"path":1512,"stem":1513},"ViewModel Implementation — Від BaseViewModel до валідації","\u002Fcsharp\u002Fdesktop-ui\u002Fviewmodel-implementation","01.csharp\u002F12.desktop-ui\u002F23.viewmodel-implementation",{"title":1515,"path":1516,"stem":1517},"Commands — Від event handlers до декларативних команд","\u002Fcsharp\u002Fdesktop-ui\u002Fcommands","01.csharp\u002F12.desktop-ui\u002F24.commands",{"title":1519,"path":1520,"stem":1521},"MVVM Toolkit — MVVM без boilerplate через Source Generators","\u002Fcsharp\u002Fdesktop-ui\u002Fmvvm-toolkit","01.csharp\u002F12.desktop-ui\u002F25.mvvm-toolkit",{"title":1523,"path":1524,"stem":1525},"Messenger Pattern — Комунікація між ViewModel без прямих посилань","\u002Fcsharp\u002Fdesktop-ui\u002Fmessenger-pattern","01.csharp\u002F12.desktop-ui\u002F26.messenger-pattern",{"title":1527,"path":1528,"stem":1529},"Стилі WPF — CSS для десктопу","\u002Fcsharp\u002Fdesktop-ui\u002Fstyles-basics","01.csharp\u002F12.desktop-ui\u002F27.styles-basics",{"title":1531,"path":1532,"stem":1533},"CSS-like стилі Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002F27a.avalonia-css-styling","01.csharp\u002F12.desktop-ui\u002F27a.avalonia-css-styling",{"title":1535,"path":1536,"stem":1537},"Control Templates — Частина 1. Концепція та TemplateBinding","\u002Fcsharp\u002Fdesktop-ui\u002Fcontrol-templates-part1","01.csharp\u002F12.desktop-ui\u002F28.control-templates-part1",{"title":1539,"path":1540,"stem":1541},"Control Templates — Частина 2. Named Parts та ContentPresenter","\u002Fcsharp\u002Fdesktop-ui\u002Fcontrol-templates-part2","01.csharp\u002F12.desktop-ui\u002F28.control-templates-part2",{"title":1543,"path":1544,"stem":1545},"Control Themes в Avalonia — нова ера стилізації","\u002Fcsharp\u002Fdesktop-ui\u002F28a.avalonia-control-themes","01.csharp\u002F12.desktop-ui\u002F28a.avalonia-control-themes",{"title":1547,"path":1548,"stem":1549},"Triggers та Visual State Manager у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Ftriggers-visual-states","01.csharp\u002F12.desktop-ui\u002F29.triggers-visual-states",{"title":1551,"path":1552,"stem":1553},"Pseudo-classes в Avalonia — замість WPF Triggers","\u002Fcsharp\u002Fdesktop-ui\u002F29a.avalonia-pseudo-classes","01.csharp\u002F12.desktop-ui\u002F29a.avalonia-pseudo-classes",{"title":1555,"path":1556,"stem":1557},"Теми та ресурсні словники у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fresources-themes","01.csharp\u002F12.desktop-ui\u002F30.resources-themes",{"title":1559,"path":1560,"stem":1561},"Avalonia Themes — Fluent Design та система тематизації","\u002Fcsharp\u002Fdesktop-ui\u002F30a.avalonia-themes-fluent","01.csharp\u002F12.desktop-ui\u002F30a.avalonia-themes-fluent",{"title":1563,"path":1564,"stem":1565},"Контроли колекцій — глибоке занурення","\u002Fcsharp\u002Fdesktop-ui\u002Fcollection-controls","01.csharp\u002F12.desktop-ui\u002F31.collection-controls",{"title":1567,"path":1568,"stem":1569},"DataGrid — колонки та базове відображення","\u002Fcsharp\u002Fdesktop-ui\u002Fdatagrid-part1","01.csharp\u002F12.desktop-ui\u002F32.datagrid-part1",{"title":1571,"path":1572,"stem":1573},"DataGrid — сортування, фільтрація, редагування","\u002Fcsharp\u002Fdesktop-ui\u002Fdatagrid-part2","01.csharp\u002F12.desktop-ui\u002F32.datagrid-part2",{"title":1575,"path":1576,"stem":1577},"TreeView та GridView","\u002Fcsharp\u002Fdesktop-ui\u002Ftreeview-listview","01.csharp\u002F12.desktop-ui\u002F33.treeview-listview",{"title":1579,"path":1580,"stem":1581},"Меню, Toolbar, ContextMenu, StatusBar","\u002Fcsharp\u002Fdesktop-ui\u002Fmenus-toolbars","01.csharp\u002F12.desktop-ui\u002F34.menus-toolbars",{"title":1583,"path":1584,"stem":1585},"Навігація та керування вікнами. Частина 1: вікна та сторінки","\u002Fcsharp\u002Fdesktop-ui\u002Fnavigation-windows-part1","01.csharp\u002F12.desktop-ui\u002F35.navigation-windows-part1",{"title":1587,"path":1588,"stem":1589},"Навігація та керування вікнами. Частина 2: MVVM-навігація","\u002Fcsharp\u002Fdesktop-ui\u002Fnavigation-windows-part2","01.csharp\u002F12.desktop-ui\u002F35.navigation-windows-part2",{"title":1591,"path":1592,"stem":1593},"Avalonia — Навігація та діалоги","\u002Fcsharp\u002Fdesktop-ui\u002F35a.avalonia-navigation-dialogs","01.csharp\u002F12.desktop-ui\u002F35a.avalonia-navigation-dialogs",{"title":1595,"path":1596,"stem":1597},"Діалоги та File Pickers у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fdialogs-file-pickers","01.csharp\u002F12.desktop-ui\u002F36.dialogs-file-pickers",{"title":1599,"path":1600,"stem":1601},"UserControl: компонентний підхід у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fuser-controls","01.csharp\u002F12.desktop-ui\u002F37.user-controls",{"title":1603,"path":1604,"stem":1605},"Custom Controls: Lookless Controls у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fcustom-controls","01.csharp\u002F12.desktop-ui\u002F38.custom-controls",{"title":1607,"path":1608,"stem":1609},"Avalonia TemplatedControl — Lookless Controls","\u002Fcsharp\u002Fdesktop-ui\u002F38a.avalonia-templated-controls","01.csharp\u002F12.desktop-ui\u002F38a.avalonia-templated-controls",{"title":1611,"path":1612,"stem":1613},"Анімації у WPF: Storyboard та Easing Functions","\u002Fcsharp\u002Fdesktop-ui\u002Fanimations-transitions","01.csharp\u002F12.desktop-ui\u002F39.animations-transitions",{"title":1615,"path":1616,"stem":1617},"Анімації в Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002F39a.avalonia-animations","01.csharp\u002F12.desktop-ui\u002F39a.avalonia-animations",{"title":1619,"path":1620,"stem":1621},"2D Графіка та Мультимедіа у WPF","\u002Fcsharp\u002Fdesktop-ui\u002Fmedia-graphics","01.csharp\u002F12.desktop-ui\u002F40.media-graphics",{"title":1623,"path":1624,"stem":1625},"Dependency Injection у WPF та Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002Fdi-integration","01.csharp\u002F12.desktop-ui\u002F41.di-integration",{"title":1627,"path":1628,"stem":1629},"SQLite та EF Core у десктопних додатках","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-persistence-part1","01.csharp\u002F12.desktop-ui\u002F42.data-persistence-part1",{"title":1631,"path":1632,"stem":1633},"Repository Pattern та Unit of Work","\u002Fcsharp\u002Fdesktop-ui\u002Fdata-persistence-part2","01.csharp\u002F12.desktop-ui\u002F43.data-persistence-part2",{"title":1635,"path":1636,"stem":1637},"Тестування ViewModels","\u002Fcsharp\u002Fdesktop-ui\u002Fviewmodel-testing","01.csharp\u002F12.desktop-ui\u002F44.viewmodel-testing",{"title":1639,"path":1640,"stem":1641},"Avalonia Headless Testing — тестування UI без вікон","\u002Fcsharp\u002Fdesktop-ui\u002F44a.avalonia-headless-testing","01.csharp\u002F12.desktop-ui\u002F44a.avalonia-headless-testing",{"title":1643,"path":1644,"stem":1645},"Кросплатформна розробка з Avalonia","\u002Fcsharp\u002Fdesktop-ui\u002Favalonia-cross-platform","01.csharp\u002F12.desktop-ui\u002F45.avalonia-cross-platform",{"title":1647,"path":1648,"stem":1649},"Пакування та розгортання Avalonia додатків","\u002Fcsharp\u002Fdesktop-ui\u002Favalonia-packaging-deployment","01.csharp\u002F12.desktop-ui\u002F46.avalonia-packaging-deployment",{"title":1651,"path":1652,"stem":1653},"Розгортання WPF застосунків","\u002Fcsharp\u002Fdesktop-ui\u002Fwpf-packaging-deployment","01.csharp\u002F12.desktop-ui\u002F47.wpf-packaging-deployment",{"title":1655,"icon":658,"path":1656,"stem":1657,"children":1658,"page":59},"Network Programming","\u002Fcsharp\u002Fnetwork-programming","01.csharp\u002F13.network-programming",[1659,1663,1667,1671,1675,1679,1683,1687,1691,1695,1699],{"title":1660,"path":1661,"stem":1662},"Основи комп'ютерних мереж","\u002Fcsharp\u002Fnetwork-programming\u002Ffoundations","01.csharp\u002F13.network-programming\u002F01.foundations",{"title":1664,"path":1665,"stem":1666},"Модель OSI та стек TCP\u002FIP","\u002Fcsharp\u002Fnetwork-programming\u002Fosi-model","01.csharp\u002F13.network-programming\u002F02.osi-model",{"title":1668,"path":1669,"stem":1670},"IP-протокол та адресація","\u002Fcsharp\u002Fnetwork-programming\u002Fip-addressing","01.csharp\u002F13.network-programming\u002F03.ip-addressing",{"title":1672,"path":1673,"stem":1674},"UDP — протокол без з'єднання","\u002Fcsharp\u002Fnetwork-programming\u002Fudp","01.csharp\u002F13.network-programming\u002F05.udp",{"title":1676,"path":1677,"stem":1678},"UDP Broadcast та Multicast","\u002Fcsharp\u002Fnetwork-programming\u002Fudp-broadcast-multicast","01.csharp\u002F13.network-programming\u002F06.udp-broadcast-multicast",{"title":1680,"path":1681,"stem":1682},"HTTP — протокол вебу","\u002Fcsharp\u002Fnetwork-programming\u002Fhttp-fundamentals","01.csharp\u002F13.network-programming\u002F07.http-fundamentals",{"title":1684,"path":1685,"stem":1686},"HttpListener — вбудований HTTP-сервер .NET","\u002Fcsharp\u002Fnetwork-programming\u002F07a.http-listener","01.csharp\u002F13.network-programming\u002F07a.http-listener",{"title":1688,"path":1689,"stem":1690},"HTTP Advanced — cookies, аутентифікація та HTTPS","\u002Fcsharp\u002Fnetwork-programming\u002Fhttp-advanced","01.csharp\u002F13.network-programming\u002F08.http-advanced",{"title":1692,"path":1693,"stem":1694},"SMTP та протоколи електронної пошти","\u002Fcsharp\u002Fnetwork-programming\u002Fsmtp","01.csharp\u002F13.network-programming\u002F09.smtp",{"title":1696,"path":1697,"stem":1698},"WebSocket — повнодуплексний протокол реального часу","\u002Fcsharp\u002Fnetwork-programming\u002Fwebsockets","01.csharp\u002F13.network-programming\u002F10.websockets",{"title":1700,"path":1701,"stem":1702},"TLS\u002FSSL — криптографічний захист мережевих з'єднань","\u002Fcsharp\u002Fnetwork-programming\u002Ftls-ssl","01.csharp\u002F13.network-programming\u002F11.tls-ssl",{"title":1704,"path":1705,"stem":1706},"C# & .NET: The Ultimate Roadmap","\u002Fcsharp\u002Froadmap","01.csharp\u002Froadmap",{"title":1708,"icon":1709,"path":1710,"stem":1711,"children":1712,"page":59},"C++","i-devicon-cplusplus","\u002Fcpp","02.cpp",[1713,1717,1721,1725,1729,1733,1737,1741,1745,1748,1752,1756,1760,1764,1768,1772,1776,1780,1784,1788,1792,1796,1800,1804,1808,1812,1816,1820,1824,1828,1832,1836,1840,1844,1848,1852,1856,1860,1864,1868,1872,1876,1880,1884,1888,1892,1896,1900,1904,1908],{"title":1714,"path":1715,"stem":1716},"Вступ у програмування та алгоритми","\u002Fcpp\u002Fintro-algorithms","02.cpp\u002F01.intro-algorithms",{"title":1718,"path":1719,"stem":1720},"Code Style: угоди про оформлення коду","\u002Fcpp\u002Fcode-style","02.cpp\u002F02.code-style",{"title":1722,"path":1723,"stem":1724},"Середовище розробки та перший проєкт","\u002Fcpp\u002Fide-setup","02.cpp\u002F03.ide-setup",{"title":1726,"path":1727,"stem":1728},"Вивід даних на екран","\u002Fcpp\u002Fdata-output","02.cpp\u002F04.data-output",{"title":1730,"path":1731,"stem":1732},"Типи даних, змінні та константи","\u002Fcpp\u002Fdata-types-variables","02.cpp\u002F05.data-types-variables",{"title":1734,"path":1735,"stem":1736},"Ввід даних з клавіатури","\u002Fcpp\u002Fdata-input","02.cpp\u002F06.data-input",{"title":1738,"path":1739,"stem":1740},"Оператори, перетворення типів та логічні операції","\u002Fcpp\u002Foperators-type-conversion","02.cpp\u002F07.operators-type-conversion",{"title":1742,"path":1743,"stem":1744},"Цикли","\u002Fcpp\u002Floops","02.cpp\u002F08.loops",{"title":32,"path":1746,"stem":1747},"\u002Fcpp\u002Farrays","02.cpp\u002F09.arrays",{"title":1749,"path":1750,"stem":1751},"Алгоритми сортування та аналіз складності","\u002Fcpp\u002Fsorting","02.cpp\u002F10.sorting",{"title":1753,"path":1754,"stem":1755},"Алгоритми пошуку","\u002Fcpp\u002Fsearching","02.cpp\u002F11.searching",{"title":1757,"path":1758,"stem":1759},"Функції: основи","\u002Fcpp\u002Ffunctions-basics","02.cpp\u002F12.functions-basics",{"title":1761,"path":1762,"stem":1763},"Функції: прототипи, область видимості та додаткові можливості","\u002Fcpp\u002Ffunctions-scope","02.cpp\u002F13.functions-scope",{"title":1765,"path":1766,"stem":1767},"Функції: перевантаження та шаблони","\u002Fcpp\u002Ffunctions-overloading-templates","02.cpp\u002F14.functions-overloading-templates",{"title":1769,"path":1770,"stem":1771},"Вказівники: основи","\u002Fcpp\u002Fpointers-basics","02.cpp\u002F15.pointers-basics",{"title":1773,"path":1774,"stem":1775},"Посилання (References)","\u002Fcpp\u002Freferences","02.cpp\u002F16.references",{"title":1777,"path":1778,"stem":1779},"Вказівники, const і масиви","\u002Fcpp\u002Fpointers-const-arrays","02.cpp\u002F17.pointers-const-arrays",{"title":1781,"path":1782,"stem":1783},"Адресна арифметика","\u002Fcpp\u002Fpointer-arithmetic","02.cpp\u002F18.pointer-arithmetic",{"title":1785,"path":1786,"stem":1787},"Динамічна пам'ять","\u002Fcpp\u002Fdynamic-memory","02.cpp\u002F19.dynamic-memory",{"title":1789,"path":1790,"stem":1791},"Вказівники типу void","\u002Fcpp\u002Fvoid-pointers","02.cpp\u002F20.void-pointers",{"title":1793,"path":1794,"stem":1795},"Вказівники на вказівники","\u002Fcpp\u002Fpointers-to-pointers","02.cpp\u002F21.pointers-to-pointers",{"title":1797,"path":1798,"stem":1799},"Оператор доступу до членів через вказівник (->)","\u002Fcpp\u002Fmember-access-operator","02.cpp\u002F22.member-access-operator",{"title":1801,"path":1802,"stem":1803},"Цикл for-each (Range-based for)","\u002Fcpp\u002Fforeach-loop","02.cpp\u002F23.foreach-loop",{"title":1805,"path":1806,"stem":1807},"Вказівники на функції","\u002Fcpp\u002Ffunction-pointers","02.cpp\u002F24.function-pointers",{"title":1809,"path":1810,"stem":1811},"Лямбда-вирази","\u002Fcpp\u002Flambdas","02.cpp\u002F25.lambdas",{"title":1813,"path":1814,"stem":1815},"Лямбда-захоплення","\u002Fcpp\u002Flambda-captures","02.cpp\u002F26.lambda-captures",{"title":1817,"path":1818,"stem":1819},"Еліпсис","\u002Fcpp\u002Fellipsis","02.cpp\u002F27.ellipsis",{"title":1821,"path":1822,"stem":1823},"Безпечні альтернативи еліпсису","\u002Fcpp\u002F27a.ellipsis","02.cpp\u002F27a.ellipsis",{"title":1825,"path":1826,"stem":1827},"Аргументи командного рядка","\u002Fcpp\u002Fcommand-line-arguments","02.cpp\u002F28.command-line-arguments",{"title":1829,"path":1830,"stem":1831},"Перерахування (enum)","\u002Fcpp\u002Fenum","02.cpp\u002F29.enum",{"title":1833,"path":1834,"stem":1835},"Класи-перерахування (enum class)","\u002Fcpp\u002Fenum-class","02.cpp\u002F30.enum-class",{"title":1837,"path":1838,"stem":1839},"Псевдоніми типів (typedef і using)","\u002Fcpp\u002Ftype-aliases","02.cpp\u002F31.type-aliases",{"title":1841,"path":1842,"stem":1843},"Системи числення та двійкова арифметика","\u002Fcpp\u002Fnumber-systems","02.cpp\u002F32.number-systems",{"title":1845,"path":1846,"stem":1847},"Структури (struct): агрегування даних","\u002Fcpp\u002Fstruct","02.cpp\u002F33.struct",{"title":1849,"path":1850,"stem":1851},"Структури у функціях","\u002Fcpp\u002Fstruct-functions","02.cpp\u002F34.struct-functions",{"title":1853,"path":1854,"stem":1855},"Масиви структур і вкладені структури","\u002Fcpp\u002Fstruct-arrays","02.cpp\u002F35.struct-arrays",{"title":1857,"path":1858,"stem":1859},"Патерни struct та межі застосування","\u002Fcpp\u002Fstruct-patterns","02.cpp\u002F36.struct-patterns",{"title":1861,"path":1862,"stem":1863},"Символи та таблиця ASCII","\u002Fcpp\u002Fascii-characters","02.cpp\u002F37.ascii-characters",{"title":1865,"path":1866,"stem":1867},"Unicode та кодування UTF","\u002Fcpp\u002Funicode-utf","02.cpp\u002F38.unicode-utf",{"title":1869,"path":1870,"stem":1871},"C-style рядки","\u002Fcpp\u002Fc-strings","02.cpp\u002F39.c-strings",{"title":1873,"path":1874,"stem":1875},"Вступ до std::string","\u002Fcpp\u002Fstd-string-intro","02.cpp\u002F40.std-string-intro",{"title":1877,"path":1878,"stem":1879},"Довжина, ємність та доступ до символів std::string","\u002Fcpp\u002Fstd-string-capacity-access","02.cpp\u002F41.std-string-capacity-access",{"title":1881,"path":1882,"stem":1883},"Модифікація std::string: присвоювання, додавання, вставка, видалення та заміна","\u002Fcpp\u002Fstd-string-modification","02.cpp\u002F42.std-string-modification",{"title":1885,"path":1886,"stem":1887},"Пошук у std::string: find, npos та практичні патерни","\u002Fcpp\u002Fstd-string-search","02.cpp\u002F43.std-string-search",{"title":1889,"path":1890,"stem":1891},"std::string_view: невласницький погляд на рядок без копіювання","\u002Fcpp\u002Fstd-string-view","02.cpp\u002F44.std-string-view",{"title":1893,"path":1894,"stem":1895},"Об'єднання (union): один блок пам'яті, кілька інтерпретацій","\u002Fcpp\u002Funion","02.cpp\u002F45.union",{"title":1897,"path":1898,"stem":1899},"Організація коду: файли, препроцесор, простори імен","\u002Fcpp\u002Fmultifile-programs","02.cpp\u002F46.multifile-programs",{"title":1901,"path":1902,"stem":1903},"Робота з файлами: C-стиль (stdio.h)","\u002Fcpp\u002Fc-style-files","02.cpp\u002F47.c-style-files",{"title":1905,"path":1906,"stem":1907},"Робота з файлами: C++-стиль (fstream)","\u002Fcpp\u002Fcpp-style-files","02.cpp\u002F48.cpp-style-files",{"title":1909,"path":1910,"stem":1911},"План навчання: Курс C++ — Продовження (Статті 29–60+)","\u002Fcpp\u002Fcurriculum-plan","02.cpp\u002Fcurriculum-plan",{"title":1913,"icon":1914,"path":1915,"stem":1916,"children":1917,"page":59},"JavaScript","i-devicon-javascript","\u002Fjavascript","03.javascript",[1918,1944,1998,2020,2324,2362],{"title":1919,"icon":1920,"path":1921,"stem":1922,"children":1923,"page":59},"Events","i-lucide-mouse-pointer-click","\u002Fjavascript\u002Fevents","03.javascript\u002F01.events",[1924,1928,1932,1936,1940],{"title":1925,"path":1926,"stem":1927},"Вступ до подій браузера","\u002Fjavascript\u002Fevents\u002Fintro","03.javascript\u002F01.events\u002F01.intro",{"title":1929,"path":1930,"stem":1931},"Бульбашковий механізм (Bubbling) та занурення (Capturing)","\u002Fjavascript\u002Fevents\u002Fbubbling-capturing","03.javascript\u002F01.events\u002F02.bubbling-capturing",{"title":1933,"path":1934,"stem":1935},"Делегування подій (Event Delegation)","\u002Fjavascript\u002Fevents\u002Fdelegate-events","03.javascript\u002F01.events\u002F03.delegate-events",{"title":1937,"path":1938,"stem":1939},"Типові дії браузера та preventDefault()","\u002Fjavascript\u002Fevents\u002Fprevent-default","03.javascript\u002F01.events\u002F04.prevent-default",{"title":1941,"path":1942,"stem":1943},"Запуск користувацьких подій (Custom Events)","\u002Fjavascript\u002Fevents\u002Fcustom-events","03.javascript\u002F01.events\u002F05.custom-events",{"title":1945,"icon":1946,"path":1947,"stem":1948,"children":1949,"page":59},"Network","i-lucide-globe","\u002Fjavascript\u002Fnetwork","03.javascript\u002F02.network",[1950,1954,1958,1962,1966,1970,1974,1978,1982,1986,1990,1994],{"title":1951,"path":1952,"stem":1953},"Fetch API - Сучасний підхід до HTTP-запитів","\u002Fjavascript\u002Fnetwork\u002F01-fetch-api","03.javascript\u002F02.network\u002F01-fetch-api",{"title":1955,"path":1956,"stem":1957},"FormData - Робота з формами та файлами","\u002Fjavascript\u002Fnetwork\u002F02-formdata","03.javascript\u002F02.network\u002F02-formdata",{"title":1959,"path":1960,"stem":1961},"Відстеження прогресу завантаження","\u002Fjavascript\u002Fnetwork\u002F03-download-progress","03.javascript\u002F02.network\u002F03-download-progress",{"title":1963,"path":1964,"stem":1965},"Переривання fetch-запитів","\u002Fjavascript\u002Fnetwork\u002F04-abort-requests","03.javascript\u002F02.network\u002F04-abort-requests",{"title":1967,"path":1968,"stem":1969},"CORS - Запити між різними джерелами","\u002Fjavascript\u002Fnetwork\u002F05-cors","03.javascript\u002F02.network\u002F05-cors",{"title":1971,"path":1972,"stem":1973},"Fetch API - Повний довідник опцій","\u002Fjavascript\u002Fnetwork\u002F06-fetch-options","03.javascript\u002F02.network\u002F06-fetch-options",{"title":1975,"path":1976,"stem":1977},"URL Objects - Робота з посиланнями","\u002Fjavascript\u002Fnetwork\u002F07-url-objects","03.javascript\u002F02.network\u002F07-url-objects",{"title":1979,"path":1980,"stem":1981},"XMLHttpRequest - AJAX та низькорівневі запити","\u002Fjavascript\u002Fnetwork\u002F08-xmlhttprequest","03.javascript\u002F02.network\u002F08-xmlhttprequest",{"title":1983,"path":1984,"stem":1985},"Відновлюване завантаження файлів","\u002Fjavascript\u002Fnetwork\u002F09-resumable-upload","03.javascript\u002F02.network\u002F09-resumable-upload",{"title":1987,"path":1988,"stem":1989},"Cookies, document.cookie та світ після \"Cookiepocalypse\"","\u002Fjavascript\u002Fnetwork\u002F10-cookies","03.javascript\u002F02.network\u002F10-cookies",{"title":1991,"path":1992,"stem":1993},"js-cookie: Керування Cookies без Болю","\u002Fjavascript\u002Fnetwork\u002F11-js-cookie","03.javascript\u002F02.network\u002F11-js-cookie",{"title":1995,"path":1996,"stem":1997},"Axios: Потужний HTTP-клієнт для JavaScript","\u002Fjavascript\u002Fnetwork\u002F12-axios","03.javascript\u002F02.network\u002F12-axios",{"title":1999,"icon":2000,"path":2001,"stem":2002,"children":2003,"page":59},"Bom","i-lucide-monitor","\u002Fjavascript\u002Fbom","03.javascript\u002F03.bom",[2004,2008,2012,2016],{"title":2005,"path":2006,"stem":2007},"LocalStorage, SessionStorage та patterns збереження даних","\u002Fjavascript\u002Fbom\u002F01-localstorage","03.javascript\u002F03.bom\u002F01-localstorage",{"title":2009,"path":2010,"stem":2011},"Location Object - Керування адресою сторінки","\u002Fjavascript\u002Fbom\u002F02-location-object","03.javascript\u002F03.bom\u002F02-location-object",{"title":2013,"path":2014,"stem":2015},"History API - Керування історією браузера","\u002Fjavascript\u002Fbom\u002F03-history-api","03.javascript\u002F03.bom\u002F03-history-api",{"title":2017,"path":2018,"stem":2019},"Navigator Object - Ідентифікація та Можливості Пристрою","\u002Fjavascript\u002Fbom\u002F04-navigator-object","03.javascript\u002F03.bom\u002F04-navigator-object",{"title":2021,"icon":2022,"path":2023,"stem":2024,"children":2025},"React","i-devicon-react","\u002Fjavascript\u002Freact","03.javascript\u002F04.react\u002Findex",[2026,2027,2031,2035,2039,2043,2106,2141,2293],{"title":2021,"path":2023,"stem":2024},{"title":2028,"path":2029,"stem":2030},"Робота з Формами в React","\u002Fjavascript\u002Freact\u002Freact-forms","03.javascript\u002F04.react\u002F01.react-forms",{"title":2032,"path":2033,"stem":2034},"React Hook Form: Професійна Робота з Формами","\u002Fjavascript\u002Freact\u002Freact-hook-form","03.javascript\u002F04.react\u002F02.react-hook-form",{"title":2036,"path":2037,"stem":2038},"React Hook Form: Глибоке Розуміння Архітектури та Оптимізації","\u002Fjavascript\u002Freact\u002Freact-hook-form-new","03.javascript\u002F04.react\u002F02.react-hook-form-new",{"title":2040,"path":2041,"stem":2042},"Axios та React: Професійна Архітектура Запитів","\u002Fjavascript\u002Freact\u002Fdata-fetching-axios","03.javascript\u002F04.react\u002F03.data-fetching-axios",{"title":2044,"icon":132,"path":2045,"stem":2046,"children":2047},"Tanstack Query","\u002Fjavascript\u002Freact\u002Ftanstack-query","03.javascript\u002F04.react\u002F04.tanstack-query\u002Findex",[2048,2050,2054,2058,2062,2066,2070,2074,2078,2082,2086,2090,2094,2098,2102],{"title":2049,"path":2045,"stem":2046},"TanStack Query: Майстерність Керування Станом Сервера",{"title":2051,"path":2052,"stem":2053},"Парадигма Server State: Чому useEffect недостатньо","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fserver-state-paradigm","03.javascript\u002F04.react\u002F04.tanstack-query\u002F01.server-state-paradigm",{"title":2055,"path":2056,"stem":2057},"Встановлення та Налаштування: Фундамент","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Finstallation-and-devtools","03.javascript\u002F04.react\u002F04.tanstack-query\u002F02.installation-and-devtools",{"title":2059,"path":2060,"stem":2061},"Основи Запитів та Магія Ключів","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fquery-basics-and-keys","03.javascript\u002F04.react\u002F04.tanstack-query\u002F03.query-basics-and-keys",{"title":2063,"path":2064,"stem":2065},"Синхронізація Даних: Життєвий Цикл Запиту","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fdata-synchronization","03.javascript\u002F04.react\u002F04.tanstack-query\u002F04.data-synchronization",{"title":2067,"path":2068,"stem":2069},"Мутації та Інвалідація: Зміна Даних","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fmutations-and-invalidation","03.javascript\u002F04.react\u002F04.tanstack-query\u002F05.mutations-and-invalidation",{"title":2071,"path":2072,"stem":2073},"Оптимістичні Оновлення: Швидше за Світло","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Foptimistic-updates","03.javascript\u002F04.react\u002F04.tanstack-query\u002F06.optimistic-updates",{"title":2075,"path":2076,"stem":2077},"Пагінація та Infinite Scroll","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fpagination-and-load-more","03.javascript\u002F04.react\u002F04.tanstack-query\u002F07.pagination-and-load-more",{"title":2079,"path":2080,"stem":2081},"Просунуті Патерни та Оптимізація","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fadvanced-patterns","03.javascript\u002F04.react\u002F04.tanstack-query\u002F08.advanced-patterns",{"title":2083,"path":2084,"stem":2085},"Архітектура та Best Practices","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Farchitecture-and-best-practices","03.javascript\u002F04.react\u002F04.tanstack-query\u002F09.architecture-and-best-practices",{"title":2087,"path":2088,"stem":2089},"Server-Side Rendering (SSR) та Гідратація","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fserver-side-rendering","03.javascript\u002F04.react\u002F04.tanstack-query\u002F10.server-side-rendering",{"title":2091,"path":2092,"stem":2093},"Стратегії Тестування","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Ftesting-strategies","03.javascript\u002F04.react\u002F04.tanstack-query\u002F11.testing-strategies",{"title":2095,"path":2096,"stem":2097},"Аутентифікація та Обробка Помилок","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fauthentication-and-errors","03.javascript\u002F04.react\u002F04.tanstack-query\u002F12.authentication-and-errors",{"title":2099,"path":2100,"stem":2101},"React Suspense та Майбутнє","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Freact-suspense","03.javascript\u002F04.react\u002F04.tanstack-query\u002F13.react-suspense",{"title":2103,"path":2104,"stem":2105},"Глибоке Занурення в Продуктивність","\u002Fjavascript\u002Freact\u002Ftanstack-query\u002Fperformance-deep-dive","03.javascript\u002F04.react\u002F04.tanstack-query\u002F14.performance-deep-dive",{"title":2107,"icon":2022,"path":2108,"stem":2109,"children":2110},"React Router","\u002Fjavascript\u002Freact\u002Freact-router","03.javascript\u002F04.react\u002F05.react-router\u002Findex",[2111,2113,2117,2121,2125,2129,2133,2137],{"title":2112,"path":2108,"stem":2109},"React Router: Навігаційна система сучасного вебу",{"title":2114,"path":2115,"stem":2116},"Налаштування та Базовий Роутинг","\u002Fjavascript\u002Freact\u002Freact-router\u002Fsetup-and-basic-routing","03.javascript\u002F04.react\u002F05.react-router\u002F01.setup-and-basic-routing",{"title":2118,"path":2119,"stem":2120},"Динамічна Навігація","\u002Fjavascript\u002Freact\u002Freact-router\u002Fnavigation-and-links","03.javascript\u002F04.react\u002F05.react-router\u002F02.navigation-and-links",{"title":2122,"path":2123,"stem":2124},"Вкладені Маршрути та Макети","\u002Fjavascript\u002Freact\u002Freact-router\u002Fnested-routes-and-layouts","03.javascript\u002F04.react\u002F05.react-router\u002F03.nested-routes-and-layouts",{"title":2126,"path":2127,"stem":2128},"Динамічні Маршрути та Параметри","\u002Fjavascript\u002Freact\u002Freact-router\u002Fdynamic-routing","03.javascript\u002F04.react\u002F05.react-router\u002F04.dynamic-routing",{"title":2130,"path":2131,"stem":2132},"Data APIs: Loaders та Actions","\u002Fjavascript\u002Freact\u002Freact-router\u002Fdata-loading","03.javascript\u002F04.react\u002F05.react-router\u002F05.data-loading",{"title":2134,"path":2135,"stem":2136},"Просунуті Патерни","\u002Fjavascript\u002Freact\u002Freact-router\u002Fadvanced-patterns","03.javascript\u002F04.react\u002F05.react-router\u002F06.advanced-patterns",{"title":2138,"path":2139,"stem":2140},"Legacy Routing: Компонентний підхід","\u002Fjavascript\u002Freact\u002Freact-router\u002Flegacy-routing","03.javascript\u002F04.react\u002F05.react-router\u002F07.legacy-routing",{"title":2142,"icon":132,"path":2143,"stem":2144,"children":2145},"Redux","\u002Fjavascript\u002Freact\u002Fredux","03.javascript\u002F04.react\u002F06.redux\u002Findex",[2146,2148,2164,2193,2202,2223,2239,2268],{"title":2147,"path":2143,"stem":2144},"Redux: Еволюція управління станом",{"title":14,"icon":15,"path":2149,"stem":2150,"children":2151,"page":59},"\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals",[2152,2156,2160],{"title":2153,"path":2154,"stem":2155},"Вступ до State Management","\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals\u002Fintro-state-management","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals\u002F01.intro-state-management",{"title":2157,"path":2158,"stem":2159},"Філософія Redux та Три Принципи","\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals\u002Fredux-philosophy","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals\u002F02.redux-philosophy",{"title":2161,"path":2162,"stem":2163},"Чисті функції та Іммутабельність","\u002Fjavascript\u002Freact\u002Fredux\u002Ffundamentals\u002Fpure-functions-immutability","03.javascript\u002F04.react\u002F06.redux\u002F01.fundamentals\u002F03.pure-functions-immutability",{"title":2165,"icon":132,"path":2166,"stem":2167,"children":2168,"page":59},"Classic Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux",[2169,2173,2177,2181,2185,2189],{"title":2170,"path":2171,"stem":2172},"Створення Store (Classic Redux)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Fstore-setup","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F01.store-setup",{"title":2174,"path":2175,"stem":2176},"Actions, Constants та Action Creators","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Factions-constants","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F02.actions-constants",{"title":2178,"path":2179,"stem":2180},"Логіка Reducers","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Freducers","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F03.reducers",{"title":2182,"path":2183,"stem":2184},"Комбінування Reducers (Root Reducer)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Fdata-flow","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F04.data-flow",{"title":2186,"path":2187,"stem":2188},"Підключення до React (React-Redux)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Freact-redux-connection","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F05.react-redux-connection",{"title":2190,"path":2191,"stem":2192},"Middleware та Асинхронність (Redux Thunk)","\u002Fjavascript\u002Freact\u002Fredux\u002Fclassic-redux\u002Fmiddleware-thunk","03.javascript\u002F04.react\u002F06.redux\u002F02.classic-redux\u002F06.middleware-thunk",{"title":2194,"icon":132,"path":2195,"stem":2196,"children":2197,"page":59},"Transition To Rtk","\u002Fjavascript\u002Freact\u002Fredux\u002Ftransition-to-rtk","03.javascript\u002F04.react\u002F06.redux\u002F03.transition-to-rtk",[2198],{"title":2199,"path":2200,"stem":2201},"Проблеми класичного Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Ftransition-to-rtk\u002Fproblems-with-classic","03.javascript\u002F04.react\u002F06.redux\u002F03.transition-to-rtk\u002F01.problems-with-classic",{"title":2203,"icon":132,"path":2204,"stem":2205,"children":2206,"page":59},"Redux Toolkit","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit",[2207,2211,2215,2219],{"title":2208,"path":2209,"stem":2210},"Налаштування Store з configureStore","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fconfigure-store","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F01.configure-store",{"title":2212,"path":2213,"stem":2214},"createSlice: Революція в Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fcreate-slice","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F02.create-slice",{"title":2216,"path":2217,"stem":2218},"Асинхронність з createAsyncThunk","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fasync-thunks","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F03.async-thunks",{"title":2220,"path":2221,"stem":2222},"04. Entity Adapter: Керування нормалізованим станом","\u002Fjavascript\u002Freact\u002Fredux\u002Fredux-toolkit\u002Fentity-adapter","03.javascript\u002F04.react\u002F06.redux\u002F04.redux-toolkit\u002F04.entity-adapter",{"title":2224,"icon":92,"path":2225,"stem":2226,"children":2227,"page":59},"Advanced","\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced",[2228,2232,2236],{"title":2229,"path":2230,"stem":2231},"Мемоізація та Селектори: Повний Гайд по Reselect","\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced\u002Fselectors-reselect","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced\u002F01.selectors-reselect",{"title":2233,"path":2234,"stem":2235},"RTK Query: Архітектура Серверного Кешу","\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced\u002Frtk-query-intro","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced\u002F02.rtk-query-intro",{"title":2083,"path":2237,"stem":2238},"\u002Fjavascript\u002Freact\u002Fredux\u002Fadvanced\u002Farchitecture-best-practices","03.javascript\u002F04.react\u002F06.redux\u002F05.advanced\u002F03.architecture-best-practices",{"title":2240,"icon":132,"path":2241,"stem":2242,"children":2243,"page":59},"Project Kanban","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban",[2244,2248,2252,2256,2260,2264],{"title":2245,"path":2246,"stem":2247},"Проєкт: Kanban Board (Trello Clone)","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fproject-overview","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F01.project-overview",{"title":2249,"path":2250,"stem":2251},"Налаштування та Типізація","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fsetup-and-types","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F02.setup-and-types",{"title":2253,"path":2254,"stem":2255},"Board Slice: Серце Дошки","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fboard-slice","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F03.board-slice",{"title":2257,"path":2258,"stem":2259},"Логіка Drag & Drop","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Fdrag-and-drop-logic","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F04.drag-and-drop-logic",{"title":2261,"path":2262,"stem":2263},"Інтеграція з RTK Query","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Frtk-query-integration","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F05.rtk-query-integration",{"title":2265,"path":2266,"stem":2267},"Optimistic Updates","\u002Fjavascript\u002Freact\u002Fredux\u002Fproject-kanban\u002Foptimistic-updates","03.javascript\u002F04.react\u002F06.redux\u002F06.project-kanban\u002F06.optimistic-updates",{"title":2269,"icon":132,"path":2270,"stem":2271,"children":2272,"page":59},"Testing","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting","03.javascript\u002F04.react\u002F06.redux\u002F07.testing",[2273,2277,2281,2285,2289],{"title":2274,"path":2275,"stem":2276},"Тестування Redux","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Fintro-testing","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F01.intro-testing",{"title":2278,"path":2279,"stem":2280},"Тестування Reducers","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-reducers","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F02.testing-reducers",{"title":2282,"path":2283,"stem":2284},"Тестування Селекторів","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-selectors","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F03.testing-selectors",{"title":2286,"path":2287,"stem":2288},"Тестування Компонентів (Integration)","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-components","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F04.testing-components",{"title":2290,"path":2291,"stem":2292},"Тестування Async Thunks","\u002Fjavascript\u002Freact\u002Fredux\u002Ftesting\u002Ftesting-thunks","03.javascript\u002F04.react\u002F06.redux\u002F07.testing\u002F05.testing-thunks",{"title":2294,"icon":132,"path":2295,"stem":2296,"children":2297},"Ui Libraries","\u002Fjavascript\u002Freact\u002Fui-libraries","03.javascript\u002F04.react\u002F07.ui-libraries\u002Findex",[2298,2300,2304,2308,2312,2316,2320],{"title":2299,"path":2295,"stem":2296},"UI Бібліотеки в React",{"title":2301,"path":2302,"stem":2303},"Вступ до UI Бібліотек: Навіщо Винаходити Велосипед Двічі?","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fintroduction-to-ui-libraries","03.javascript\u002F04.react\u002F07.ui-libraries\u002F01.introduction-to-ui-libraries",{"title":2305,"path":2306,"stem":2307},"Філософія shadcn\u002Fui: \"Not a Component Library\"","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-philosophy","03.javascript\u002F04.react\u002F07.ui-libraries\u002F02.shadcn-philosophy",{"title":2309,"path":2310,"stem":2311},"Установка та Налаштування shadcn\u002Fui","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-installation","03.javascript\u002F04.react\u002F07.ui-libraries\u002F03.shadcn-installation",{"title":2313,"path":2314,"stem":2315},"Базові Компоненти shadcn\u002Fui: Фундамент Інтерфейсу","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-components-basics","03.javascript\u002F04.react\u002F07.ui-libraries\u002F04.shadcn-components-basics",{"title":2317,"path":2318,"stem":2319},"Компоненти Форм: Побудова Інтерактивних Form","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-components-forms","03.javascript\u002F04.react\u002F07.ui-libraries\u002F05.shadcn-components-forms",{"title":2321,"path":2322,"stem":2323},"Складні Компоненти: Dialog, Dropdown, Table та Command","\u002Fjavascript\u002Freact\u002Fui-libraries\u002Fshadcn-components-advanced","03.javascript\u002F04.react\u002F07.ui-libraries\u002F06.shadcn-components-advanced",{"title":2325,"icon":2326,"path":2327,"stem":2328,"children":2329,"page":59},"TypeScript","i-devicon-typescript","\u002Fjavascript\u002Ftypescript","03.javascript\u002F05.typescript",[2330,2334,2338,2342,2346,2350,2354,2358],{"title":2331,"path":2332,"stem":2333},"TypeScript: Броня для вашого коду","\u002Fjavascript\u002Ftypescript\u002Fintro-and-basic-types","03.javascript\u002F05.typescript\u002F01.intro-and-basic-types",{"title":2335,"path":2336,"stem":2337},"Майстерність Моделювання Даних: Інтерфейси та Просунуті Типи","\u002Fjavascript\u002Ftypescript\u002Finterfaces-and-advanced-types","03.javascript\u002F05.typescript\u002F02.interfaces-and-advanced-types",{"title":2339,"path":2340,"stem":2341},"Алхімія Типів: Generics та Utility Types","\u002Fjavascript\u002Ftypescript\u002Fgenerics-and-utilities","03.javascript\u002F05.typescript\u002F03.generics-and-utilities",{"title":2343,"path":2344,"stem":2345},"Архітектура та Шаблони: Класи в TypeScript","\u002Fjavascript\u002Ftypescript\u002Fclasses-and-oop","03.javascript\u002F05.typescript\u002F04.classes-and-oop",{"title":2347,"path":2348,"stem":2349},"Продакшн та Екосистема: Advanced Config & Workflow","\u002Fjavascript\u002Ftypescript\u002Fadvanced-patterns-and-config","03.javascript\u002F05.typescript\u002F05.advanced-patterns-and-config",{"title":2351,"path":2352,"stem":2353},"TypeScript у світі React","\u002Fjavascript\u002Ftypescript\u002Freact-basics","03.javascript\u002F05.typescript\u002F06.react-basics",{"title":2355,"path":2356,"stem":2357},"React + TypeScript: Продвинуті патерни","\u002Fjavascript\u002Ftypescript\u002Freact-advanced","03.javascript\u002F05.typescript\u002F07.react-advanced",{"title":2359,"path":2360,"stem":2361},"React + TypeScript: Екосистема та бібліотеки","\u002Fjavascript\u002Ftypescript\u002Freact-ecosystem","03.javascript\u002F05.typescript\u002F08.react-ecosystem",{"title":2363,"path":2364,"stem":2365},"Atomic Design","\u002Fjavascript\u002Fatomic-design","03.javascript\u002F2.atomic-design",{"title":2367,"icon":2368,"path":2369,"stem":2370,"children":2371,"page":59},"Java","i-devicon-java","\u002Fjava","04.java",[2372,2375,2378,2382,2386,2390,2394],{"title":162,"path":2373,"stem":2374},"\u002Fjava\u002Fdata-mapper-part1","04.java\u002F01.data-mapper-part1",{"title":166,"path":2376,"stem":2377},"\u002Fjava\u002Fdata-mapper-part2","04.java\u002F02.data-mapper-part2",{"title":2379,"path":2380,"stem":2381},"Service Layer: Організація бізнес-логіки","\u002Fjava\u002Fservice-layer","04.java\u002F03.service-layer",{"title":2383,"path":2384,"stem":2385},"Rich Domain Model та State Pattern","\u002Fjava\u002Frich-domain-model","04.java\u002F04.rich-domain-model",{"title":2387,"path":2388,"stem":2389},"Патерни для складної бізнес-логіки","\u002Fjava\u002Fbusiness-logic-patterns","04.java\u002F05.business-logic-patterns",{"title":2391,"path":2392,"stem":2393},"Обробка помилок та валідація","\u002Fjava\u002Ferror-handling-validation","04.java\u002F06.error-handling-validation",{"title":2395,"path":2396,"stem":2397,"children":2398,"page":59},"Проектування баз даних","\u002Fjava\u002Fpr2","04.java\u002Fpr2",[2399,2403,2407,2411,2415,2419,2423,2427,2431,2435,2439,2443,2447,2451,2455,2459,2463,2467,2471,2475,2479,2483,2487,2491,2495,2499,2503,2507,2511,2515,2519,2523,2527,2531,2535,2539,2543],{"title":2400,"path":2401,"stem":2402},"Концептуальне моделювання: Мистецтво розуміння предметної області","\u002Fjava\u002Fpr2\u002Fconceptual-modeling","04.java\u002Fpr2\u002F01.conceptual-modeling",{"title":2404,"path":2405,"stem":2406},"Логічне моделювання: Від бізнес-ідей до структур даних","\u002Fjava\u002Fpr2\u002Flogical-modeling","04.java\u002Fpr2\u002F02.logical-modeling",{"title":2408,"path":2409,"stem":2410},"Нормалізація: Гігієна даних та боротьба з аномаліями","\u002Fjava\u002Fpr2\u002Fnormalization","04.java\u002Fpr2\u002F03.normalization",{"title":2412,"path":2413,"stem":2414},"Фізична схема: Від абстракції до DDL","\u002Fjava\u002Fpr2\u002Fphysical-schema","04.java\u002Fpr2\u002F04.physical-schema",{"title":2416,"path":2417,"stem":2418},"Архітектурна класифікація таблиць","\u002Fjava\u002Fpr2\u002Ftable-classification","04.java\u002Fpr2\u002F05.table-classification",{"title":2420,"path":2421,"stem":2422},"Database Migrations: Версіонування схеми з Flyway","\u002Fjava\u002Fpr2\u002Fdatabase-migrations","04.java\u002Fpr2\u002F06.database-migrations",{"title":2424,"path":2425,"stem":2426},"А що, якби це була не реляційна БД?","\u002Fjava\u002Fpr2\u002Fbeyond-relational","04.java\u002Fpr2\u002F07.beyond-relational",{"title":2428,"path":2429,"stem":2430},"Object-Relational Impedance Mismatch: Два світи, що не хочуть дружити","\u002Fjava\u002Fpr2\u002Fimpedance-mismatch","04.java\u002Fpr2\u002F09.impedance-mismatch",{"title":2432,"path":2433,"stem":2434},"JDBC: Перший контакт із базою даних","\u002Fjava\u002Fpr2\u002Fjdbc-fundamentals","04.java\u002Fpr2\u002F10.jdbc-fundamentals",{"title":2436,"path":2437,"stem":2438},"Якість коду: Spotless, SpotBugs та SonarQube","\u002Fjava\u002Fpr2\u002F10a.code-quality","04.java\u002Fpr2\u002F10a.code-quality",{"title":2440,"path":2441,"stem":2442},"Connection Pool: Патерн Object Pool для JDBC-з'єднань","\u002Fjava\u002Fpr2\u002Fconnection-pool","04.java\u002Fpr2\u002F11.connection-pool",{"title":2444,"path":2445,"stem":2446},"Row Data Gateway: Об'єкт як обгортка рядка таблиці","\u002Fjava\u002Fpr2\u002Frow-data-gateway","04.java\u002Fpr2\u002F12.row-data-gateway",{"title":2448,"path":2449,"stem":2450},"Table Data Gateway: Фасад таблиці як архітектурний відступ","\u002Fjava\u002Fpr2\u002Ftable-data-gateway","04.java\u002Fpr2\u002F13.table-data-gateway",{"title":2452,"path":2453,"stem":2454},"Repository + Data Mapper: Правильна шарова архітектура з JDBC","\u002Fjava\u002Fpr2\u002Frepository-data-mapper","04.java\u002Fpr2\u002F14.repository-data-mapper",{"title":2456,"path":2457,"stem":2458},"Identity Map: Кешування сутностей у рамках сесії","\u002Fjava\u002Fpr2\u002Fidentity-map","04.java\u002Fpr2\u002F15.identity-map",{"title":2460,"path":2461,"stem":2462},"Unit of Work: Відстеження змін і координація JDBC-транзакцій","\u002Fjava\u002Fpr2\u002Funit-of-work","04.java\u002Fpr2\u002F16.unit-of-work",{"title":2464,"path":2465,"stem":2466},"Strategy: Замінювані SQL-стратегії для підтримки різних СУБД","\u002Fjava\u002Fpr2\u002Fstrategy-sql","04.java\u002Fpr2\u002F17.strategy-sql",{"title":2468,"path":2469,"stem":2470},"Proxy: Lazy Loading для One-To-Many колекцій","\u002Fjava\u002Fpr2\u002Fproxy-lazy-loading","04.java\u002Fpr2\u002F18.proxy-lazy-loading",{"title":2472,"path":2473,"stem":2474},"Generic Repository через Java Reflection: анотації та динамічний SQL","\u002Fjava\u002Fpr2\u002Fgeneric-repository-reflection","04.java\u002Fpr2\u002F19.generic-repository-reflection",{"title":2476,"path":2477,"stem":2478},"Specification Pattern: Композиція бізнес-правил для складних запитів","\u002Fjava\u002Fpr2\u002Fspecification-pattern","04.java\u002Fpr2\u002F20.specification-pattern",{"title":2480,"path":2481,"stem":2482},"Розширені можливості Specification Pattern: підзапити, агрегації та гібридний підхід","\u002Fjava\u002Fpr2\u002F20a.advanced-specifications","04.java\u002Fpr2\u002F20a.advanced-specifications",{"title":2484,"path":2485,"stem":2486},"Асинхронність у JDBC: Від блокуючих викликів до CompletableFuture","\u002Fjava\u002Fpr2\u002Fasynchronous-jdbc","04.java\u002Fpr2\u002F21.asynchronous-jdbc",{"title":2488,"path":2489,"stem":2490},"Інтеграційне тестування JDBC-репозиторіїв: Embedded H2 та патерн AAA","\u002Fjava\u002Fpr2\u002Fintegration-testing-h2","04.java\u002Fpr2\u002F22.integration-testing-h2",{"title":2492,"path":2493,"stem":2494},"Testcontainers: Тестування з реальною PostgreSQL у Docker-контейнерах","\u002Fjava\u002Fpr2\u002Fintegration-testing-testcontainers","04.java\u002Fpr2\u002F23.integration-testing-testcontainers",{"title":2496,"path":2497,"stem":2498},"Google Guice: Впровадження залежностей у JavaFX-проєкті","\u002Fjava\u002Fpr2\u002Fdependency-injection-guice","04.java\u002Fpr2\u002F24.dependency-injection-guice",{"title":2500,"path":2501,"stem":2502},"JavaFX: Основи побудови графічних інтерфейсів","\u002Fjava\u002Fpr2\u002Fjavafx-fundamentals","04.java\u002Fpr2\u002F25.javafx-fundamentals",{"title":2504,"path":2505,"stem":2506},"Properties та Bindings: Реактивність у JavaFX","\u002Fjava\u002Fpr2\u002Fjavafx-properties-bindings","04.java\u002Fpr2\u002F26.javafx-properties-bindings",{"title":2508,"path":2509,"stem":2510},"MVC vs MVP vs MVVM: Еволюція архітектурних патернів UI","\u002Fjava\u002Fpr2\u002Fui-architecture-patterns","04.java\u002Fpr2\u002F27.ui-architecture-patterns",{"title":2512,"path":2513,"stem":2514},"MVVM на практиці: Побудова ViewModel","\u002Fjava\u002Fpr2\u002Fmvvm-viewmodel-implementation","04.java\u002Fpr2\u002F28.mvvm-viewmodel-implementation",{"title":2516,"path":2517,"stem":2518},"View та Controller: Зв'язування з ViewModel через FXML","\u002Fjava\u002Fpr2\u002Fmvvm-view-controller","04.java\u002Fpr2\u002F29.mvvm-view-controller",{"title":2520,"path":2521,"stem":2522},"Інтеграція MVVM з Guice: Автоматична ін'єкція залежностей","\u002Fjava\u002Fpr2\u002Fmvvm-guice-integration","04.java\u002Fpr2\u002F30.mvvm-guice-integration",{"title":2524,"path":2525,"stem":2526},"Валідація та обробка помилок у MVVM","\u002Fjava\u002Fpr2\u002Fmvvm-validation-error-handling","04.java\u002Fpr2\u002F31.mvvm-validation-error-handling",{"title":2528,"path":2529,"stem":2530},"Навігація та управління екранами у JavaFX MVVM","\u002Fjava\u002Fpr2\u002Fmvvm-navigation-screen-management","04.java\u002Fpr2\u002F32.mvvm-navigation-screen-management",{"title":2532,"path":2533,"stem":2534},"Тестування JavaFX MVVM-додатків","\u002Fjava\u002Fpr2\u002Fmvvm-testing","04.java\u002Fpr2\u002F33.mvvm-testing",{"title":2536,"path":2537,"stem":2538},"Стилізація та теми у JavaFX: CSS та User Experience","\u002Fjava\u002Fpr2\u002Fjavafx-styling-themes","04.java\u002Fpr2\u002F34.javafx-styling-themes",{"title":2540,"path":2541,"stem":2542},"AtlantaFX: Сучасні теми для JavaFX додатків","\u002Fjava\u002Fpr2\u002Fatlantafx-modern-themes","04.java\u002Fpr2\u002F35.atlantafx-modern-themes",{"title":2544,"path":2545,"stem":2546},"Пакування та розповсюдження JavaFX-додатків","\u002Fjava\u002Fpr2\u002Fjar-packaging-distribution","04.java\u002Fpr2\u002F36.jar-packaging-distribution",{"title":2548,"icon":2549,"path":2550,"stem":2551,"children":2552,"page":59},"Python","i-devicon-python","\u002Fpython","05.python",[2553,2557,2560,2564,2568,2572,2576,2580,2584,2588,2592,2596,2600,2604,2608,2669],{"title":2554,"path":2555,"stem":2556},"Модулі, Пакети та Віртуальні Середовища","\u002Fpython\u002Fmodules-packages-venv","05.python\u002F00.modules-packages-venv",{"title":71,"path":2558,"stem":2559},"\u002Fpython\u002Fclasses-objects","05.python\u002F01.classes-objects",{"title":2561,"path":2562,"stem":2563},"Інкапсуляція, Керування Доступом та Властивості","\u002Fpython\u002Fencapsulation","05.python\u002F02.encapsulation",{"title":2565,"path":2566,"stem":2567},"Наслідування, MRO та суперсила super()","\u002Fpython\u002Finheritance-mro","05.python\u002F03.inheritance-mro",{"title":2569,"path":2570,"stem":2571},"Абстракція — ABC проти Статичних Протоколів (PEP 544)","\u002Fpython\u002Fabstraction-protocols","05.python\u002F04.abstraction-protocols",{"title":2573,"path":2574,"stem":2575},"Магічні методи (Dunder) та Емуляція протоколів","\u002Fpython\u002Fdunder-methods","05.python\u002F05.dunder-methods",{"title":2577,"path":2578,"stem":2579},"Декоратори та Керування життєвим циклом методів","\u002Fpython\u002Fdecorators-static-class","05.python\u002F06.decorators-static-class",{"title":2581,"path":2582,"stem":2583},"Дескриптори — Магія доступу до атрибутів","\u002Fpython\u002Fdescriptors","05.python\u002F07.descriptors",{"title":2585,"path":2586,"stem":2587},"Метакласи — Динамічне створення класів під капотом CPython","\u002Fpython\u002Fmetaclasses","05.python\u002F08.metaclasses",{"title":2589,"path":2590,"stem":2591},"Dataclasses, NamedTuple та сучасні контейнери Python","\u002Fpython\u002Fmodern-containers","05.python\u002F09.modern-containers",{"title":2593,"path":2594,"stem":2595},"GIL та модель конкурентності CPython — фундамент перед потоками і процесами","\u002Fpython\u002Fgil-concurrency-intro","05.python\u002F11.gil-concurrency-intro",{"title":2597,"path":2598,"stem":2599},"Threading — конкурентність для I\u002FO-bound задач","\u002Fpython\u002Fthreading","05.python\u002F12.threading",{"title":2601,"path":2602,"stem":2603},"Multiprocessing — справжній паралелізм для CPU-bound задач","\u002Fpython\u002Fmultiprocessing","05.python\u002F13.multiprocessing",{"title":2605,"path":2606,"stem":2607},"asyncio — кооперативна конкурентність та event loop","\u002Fpython\u002Fasyncio","05.python\u002F14.asyncio",{"title":2609,"icon":92,"path":2610,"stem":2611,"children":2612,"page":59},"FastAPI","\u002Fpython\u002Ffastapi","05.python\u002Ffastapi",[2613,2617,2621,2625,2629,2633,2637,2641,2645,2649,2653,2657,2661,2665],{"title":2614,"path":2615,"stem":2616},"Глибокий Typing та Pydantic v2 — від анотацій до валідації","\u002Fpython\u002Ffastapi\u002Ftyping-pydantic","05.python\u002Ffastapi\u002F15.typing-pydantic",{"title":2618,"path":2619,"stem":2620},"WSGI, ASGI та Python Web-екосистема","\u002Fpython\u002Ffastapi\u002Fwsgi-asgi-ecosystem","05.python\u002Ffastapi\u002F16.wsgi-asgi-ecosystem",{"title":2622,"path":2623,"stem":2624},"FastAPI: Перший додаток, Uvicorn та OpenAPI","\u002Fpython\u002Ffastapi\u002Ffastapi-intro","05.python\u002Ffastapi\u002F17.fastapi-intro",{"title":2626,"path":2627,"stem":2628},"Маршрутизація, параметри запитів та APIRouter","\u002Fpython\u002Ffastapi\u002Ffastapi-routing-params","05.python\u002Ffastapi\u002F18.fastapi-routing-params",{"title":2630,"path":2631,"stem":2632},"Pydantic v2 у FastAPI — схеми, валідація та серіалізація","\u002Fpython\u002Ffastapi\u002Ffastapi-pydantic-schemas","05.python\u002Ffastapi\u002F19.fastapi-pydantic-schemas",{"title":2634,"path":2635,"stem":2636},"Dependency Injection — серце архітектури FastAPI","\u002Fpython\u002Ffastapi\u002Ffastapi-dependency-injection","05.python\u002Ffastapi\u002F20.fastapi-dependency-injection",{"title":2638,"path":2639,"stem":2640},"Обробка помилок, Middleware та CORS у FastAPI","\u002Fpython\u002Ffastapi\u002Ffastapi-errors-middleware","05.python\u002Ffastapi\u002F21.fastapi-errors-middleware",{"title":2642,"path":2643,"stem":2644},"SQLAlchemy 2.0 — ORM, Core та Async Engine","\u002Fpython\u002Ffastapi\u002Fsqlalchemy-orm","05.python\u002Ffastapi\u002F22.sqlalchemy-orm",{"title":2646,"path":2647,"stem":2648},"Alembic — міграції бази даних","\u002Fpython\u002Ffastapi\u002Falembic-migrations","05.python\u002Ffastapi\u002F23.alembic-migrations",{"title":2650,"path":2651,"stem":2652},"Repository Pattern та Clean Architecture у FastAPI","\u002Fpython\u002Ffastapi\u002Ffastapi-repository-clean-arch","05.python\u002Ffastapi\u002F24.fastapi-repository-clean-arch",{"title":2654,"path":2655,"stem":2656},"Автентифікація та авторизація — JWT, OAuth2, RBAC","\u002Fpython\u002Ffastapi\u002Ffastapi-auth-security","05.python\u002Ffastapi\u002F25.fastapi-auth-security",{"title":2658,"path":2659,"stem":2660},"Тестування FastAPI — pytest, httpx, fixtures","\u002Fpython\u002Ffastapi\u002Ffastapi-testing","05.python\u002Ffastapi\u002F26.fastapi-testing",{"title":2662,"path":2663,"stem":2664},"Async на повну — Background Tasks, WebSockets, SSE та Celery","\u002Fpython\u002Ffastapi\u002Ffastapi-async-advanced","05.python\u002Ffastapi\u002F27.fastapi-async-advanced",{"title":2666,"path":2667,"stem":2668},"Deployment — Docker, CI\u002FCD, Monitoring","\u002Fpython\u002Ffastapi\u002Ffastapi-deployment","05.python\u002Ffastapi\u002F28.fastapi-deployment",{"title":2670,"path":2671,"stem":2672},"[object Object]","\u002Fpython\u002Foop-plan","05.python\u002Foop-plan",{"title":2674,"icon":2675,"path":2676,"stem":2677,"children":2678,"page":59},"Бази даних","i-lucide-database","\u002Fdatabases","06.databases",[2679,2709,2732,2769,2798,2816,2850,2862,2871],{"title":2680,"icon":2681,"path":2682,"stem":2683,"children":2684,"page":59},"Intro","i-lucide-play","\u002Fdatabases\u002Fintro","06.databases\u002F01.intro",[2685,2689,2693,2697,2701,2705],{"title":2686,"path":2687,"stem":2688},"Введення в теорію баз даних","\u002Fdatabases\u002Fintro\u002Fintroduction-to-databases","06.databases\u002F01.intro\u002F01.introduction-to-databases",{"title":2690,"path":2691,"stem":2692},"Реляційна модель даних","\u002Fdatabases\u002Fintro\u002Frelational-model-theory","06.databases\u002F01.intro\u002F02.relational-model-theory",{"title":2694,"path":2695,"stem":2696},"ER-моделювання","\u002Fdatabases\u002Fintro\u002Fer-modeling","06.databases\u002F01.intro\u002F03.er-modeling",{"title":2698,"path":2699,"stem":2700},"Логічне проектування БД","\u002Fdatabases\u002Fintro\u002Flogical-schema","06.databases\u002F01.intro\u002F04.logical-schema",{"title":2702,"path":2703,"stem":2704},"Класифікація таблиць","\u002Fdatabases\u002Fintro\u002Ftable-classification","06.databases\u002F01.intro\u002F05.table-classification",{"title":2706,"path":2707,"stem":2708},"PlantUML для баз даних","\u002Fdatabases\u002Fintro\u002Fplantuml-diagrams","06.databases\u002F01.intro\u002F06.plantuml-diagrams",{"title":2710,"icon":2675,"path":2711,"stem":2712,"children":2713,"page":59},"MS SQL Server Start","\u002Fdatabases\u002Fms-sql-server-start","06.databases\u002F02.ms-sql-server-start",[2714,2718,2724,2728],{"title":2715,"path":2716,"stem":2717},"Типи даних у MS SQL Server","\u002Fdatabases\u002Fms-sql-server-start\u002Fdata-types","06.databases\u002F02.ms-sql-server-start\u002F01.data-types",{"title":2719,"path":2720,"stem":2721,"children":2722},"Індекси у MS SQL Server","\u002Fdatabases\u002Fms-sql-server-start\u002Fsql-indexes","06.databases\u002F02.ms-sql-server-start\u002F02.sql-indexes",[2723],{"title":2719,"path":2720,"stem":2721},{"title":2725,"path":2726,"stem":2727},"Системні бази даних MS SQL Server","\u002Fdatabases\u002Fms-sql-server-start\u002Fsystem-databases","06.databases\u002F02.ms-sql-server-start\u002F03.system-databases",{"title":2729,"path":2730,"stem":2731},"Огляд мови SQL та запитів","\u002Fdatabases\u002Fms-sql-server-start\u002Fsql-queries-overview","06.databases\u002F02.ms-sql-server-start\u002F04.sql-queries-overview",{"title":2733,"icon":2675,"path":2734,"stem":2735,"children":2736,"page":59},"SQL","\u002Fdatabases\u002Fsql","06.databases\u002F03.sql",[2737,2741,2745,2749,2753,2757,2761,2765],{"title":2738,"path":2739,"stem":2740},"Налаштування демонстраційної бази даних","\u002Fdatabases\u002Fsql\u002Fsample-database-setup","06.databases\u002F03.sql\u002F00.sample-database-setup",{"title":2742,"path":2743,"stem":2744},"DDL - Створення таблиць (CREATE TABLE)","\u002Fdatabases\u002Fsql\u002Fddl-create-table","06.databases\u002F03.sql\u002F01.ddl-create-table",{"title":2746,"path":2747,"stem":2748},"DDL - Зміна та видалення таблиць (ALTER, DROP)","\u002Fdatabases\u002Fsql\u002Fddl-alter-drop-table","06.databases\u002F03.sql\u002F02.ddl-alter-drop-table",{"title":2750,"path":2751,"stem":2752},"SELECT запити - Основи","\u002Fdatabases\u002Fsql\u002Fselect-queries-fundamentals","06.databases\u002F03.sql\u002F03.select-queries-fundamentals",{"title":2754,"path":2755,"stem":2756},"SELECT запити - Розширені можливості","\u002Fdatabases\u002Fsql\u002Fselect-queries-advanced","06.databases\u002F03.sql\u002F04.select-queries-advanced",{"title":2758,"path":2759,"stem":2760},"INSERT запити - Додавання даних","\u002Fdatabases\u002Fsql\u002Finsert-queries","06.databases\u002F03.sql\u002F05.insert-queries",{"title":2762,"path":2763,"stem":2764},"UPDATE та DELETE запити","\u002Fdatabases\u002Fsql\u002Fupdate-delete-queries","06.databases\u002F03.sql\u002F06.update-delete-queries",{"title":2766,"path":2767,"stem":2768},"Транзакції в SQL","\u002Fdatabases\u002Fsql\u002Ftransactions","06.databases\u002F03.sql\u002F07.transactions",{"title":2770,"icon":2675,"path":2771,"stem":2772,"children":2773,"page":59},"Multi Table Databases","\u002Fdatabases\u002Fmulti-table-databases","06.databases\u002F04.multi-table-databases",[2774,2778,2782,2786,2790,2794],{"title":2775,"path":2776,"stem":2777},"Зв'язки та нормалізація БД","\u002Fdatabases\u002Fmulti-table-databases\u002Frelationships-and-normalization","06.databases\u002F04.multi-table-databases\u002F00.relationships-and-normalization",{"title":2779,"path":2780,"stem":2781},"INNER JOIN - З'єднання таблиць","\u002Fdatabases\u002Fmulti-table-databases\u002Finner-join","06.databases\u002F04.multi-table-databases\u002F01.inner-join",{"title":2783,"path":2784,"stem":2785},"OUTER JOINs - LEFT, RIGHT, FULL","\u002Fdatabases\u002Fmulti-table-databases\u002Fouter-joins","06.databases\u002F04.multi-table-databases\u002F02.outer-joins",{"title":2787,"path":2788,"stem":2789},"CROSS та SELF JOINs","\u002Fdatabases\u002Fmulti-table-databases\u002Fcross-self-joins","06.databases\u002F04.multi-table-databases\u002F03.cross-self-joins",{"title":2791,"path":2792,"stem":2793},"Підзапити (Subqueries)","\u002Fdatabases\u002Fmulti-table-databases\u002Fsubqueries","06.databases\u002F04.multi-table-databases\u002F04.subqueries",{"title":2795,"path":2796,"stem":2797},"Агрегації з JOIN","\u002Fdatabases\u002Fmulti-table-databases\u002Faggregations-with-joins","06.databases\u002F04.multi-table-databases\u002F05.aggregations-with-joins",{"title":2799,"icon":2800,"path":2801,"stem":2802,"children":2803,"page":59},"Aggregate Functions","i-lucide-calculator","\u002Fdatabases\u002Faggregate-functions","06.databases\u002F05.aggregate-functions",[2804,2808,2812],{"title":2805,"path":2806,"stem":2807},"Функції агрегування в MS SQL Server","\u002Fdatabases\u002Faggregate-functions\u002Fintroduction-aggregate-functions","06.databases\u002F05.aggregate-functions\u002F01.introduction-aggregate-functions",{"title":2809,"path":2810,"stem":2811},"Групування даних в MS SQL Server","\u002Fdatabases\u002Faggregate-functions\u002Fgrouping-data","06.databases\u002F05.aggregate-functions\u002F02.grouping-data",{"title":2813,"path":2814,"stem":2815},"Підзапити з агрегатними функціями","\u002Fdatabases\u002Faggregate-functions\u002Fsubqueries-aggregates","06.databases\u002F05.aggregate-functions\u002F03.subqueries-aggregates",{"title":2817,"icon":2818,"path":2819,"stem":2820,"children":2821,"page":59},"Тригери та зберігаємі процедури","i-lucide-database-zap","\u002Fdatabases\u002Ftriggers-stored-procedures","06.databases\u002F07.triggers-stored-procedures",[2822,2826,2830,2834,2838,2842,2846],{"title":2823,"path":2824,"stem":2825},"DML-тригери","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fdml-triggers","06.databases\u002F07.triggers-stored-procedures\u002F01.dml-triggers",{"title":2827,"path":2828,"stem":2829},"DDL-тригери","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fddl-triggers","06.databases\u002F07.triggers-stored-procedures\u002F02.ddl-triggers",{"title":2831,"path":2832,"stem":2833},"Transact-SQL розширення","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Ftransact-sql-extensions","06.databases\u002F07.triggers-stored-procedures\u002F03.transact-sql-extensions",{"title":2835,"path":2836,"stem":2837},"Транзакції","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Ftransactions","06.databases\u002F07.triggers-stored-procedures\u002F04.transactions",{"title":2839,"path":2840,"stem":2841},"Зберігаємі процедури","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fstored-procedures","06.databases\u002F07.triggers-stored-procedures\u002F05.stored-procedures",{"title":2843,"path":2844,"stem":2845},"Користувацькі функції","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fuser-defined-functions","06.databases\u002F07.triggers-stored-procedures\u002F06.user-defined-functions",{"title":2847,"path":2848,"stem":2849},"Безпека баз даних","\u002Fdatabases\u002Ftriggers-stored-procedures\u002Fsecurity","06.databases\u002F07.triggers-stored-procedures\u002F08.security",{"title":2847,"icon":793,"path":2851,"stem":2852,"children":2853,"page":59},"\u002Fdatabases\u002Fsecurity","06.databases\u002F08.security",[2854,2858],{"title":2855,"path":2856,"stem":2857},"Вступ до безпеки баз даних","\u002Fdatabases\u002Fsecurity\u002Fintroduction","06.databases\u002F08.security\u002F01.introduction",{"title":2859,"path":2860,"stem":2861},"Системні представлення та метадані","\u002Fdatabases\u002Fsecurity\u002Fsystem-views","06.databases\u002F08.security\u002F02.system-views",{"title":2863,"icon":2864,"path":2865,"stem":2866,"children":2867,"page":59},"Резервне копіювання та відновлення","i-lucide-database-backup","\u002Fdatabases\u002Fbackup-recovery","06.databases\u002F09.backup-recovery",[2868],{"title":2863,"path":2869,"stem":2870},"\u002Fdatabases\u002Fbackup-recovery\u002Fbackup-restore","06.databases\u002F09.backup-recovery\u002F01.backup-restore",{"title":2872,"icon":2873,"path":2874,"stem":2875,"children":2876,"page":59},"Повнотекстовий пошук","i-lucide-search","\u002Fdatabases\u002Ffull-text-search","06.databases\u002F10.full-text-search",[2877],{"title":2872,"path":2878,"stem":2879},"\u002Fdatabases\u002Ffull-text-search\u002Ffull-text-search","06.databases\u002F10.full-text-search\u002F01.full-text-search",{"title":2881,"icon":2882,"path":2883,"stem":2884,"children":2885,"page":59},"Tools","i-lucide-wrench","\u002Ftools","07.tools",[2886,2962],{"title":2887,"icon":2888,"path":2889,"stem":2890,"children":2891},"Docker","i-simple-icons-docker","\u002Ftools\u002Fdocker","07.tools\u002F01.docker\u002Findex",[2892,2894,2898,2902,2906,2910,2914,2918,2922,2926,2930,2934,2938,2942,2946,2950,2954,2958],{"title":2893,"path":2889,"stem":2890},"Docker: від нуля до production",{"title":2895,"path":2896,"stem":2897},"Контейнеризація — від проблеми до рішення","\u002Ftools\u002Fdocker\u002Fcontainerization-concept","07.tools\u002F01.docker\u002F01.containerization-concept",{"title":2899,"path":2900,"stem":2901},"Docker — що це і навіщо?","\u002Ftools\u002Fdocker\u002Fdocker-what-and-why","07.tools\u002F01.docker\u002F02.docker-what-and-why",{"title":2903,"path":2904,"stem":2905},"Архітектура Docker Engine","\u002Ftools\u002Fdocker\u002Fdocker-architecture","07.tools\u002F01.docker\u002F03.docker-architecture",{"title":2907,"path":2908,"stem":2909},"Встановлення Docker","\u002Ftools\u002Fdocker\u002Finstallation","07.tools\u002F01.docker\u002F04.installation",{"title":2911,"path":2912,"stem":2913},"Перший контейнер — docker run","\u002Ftools\u002Fdocker\u002Ffirst-container","07.tools\u002F01.docker\u002F05.first-container",{"title":2915,"path":2916,"stem":2917},"Життєвий цикл контейнера","\u002Ftools\u002Fdocker\u002Fcontainer-lifecycle","07.tools\u002F01.docker\u002F06.container-lifecycle",{"title":2919,"path":2920,"stem":2921},"Docker Images — фундаментальні концепції","\u002Ftools\u002Fdocker\u002Fdocker-images-fundamentals","07.tools\u002F01.docker\u002F07.docker-images-fundamentals",{"title":2923,"path":2924,"stem":2925},"Dockerfile — основи","\u002Ftools\u002Fdocker\u002Fdockerfile-basics","07.tools\u002F01.docker\u002F08.dockerfile-basics",{"title":2927,"path":2928,"stem":2929},"Dockerfile — просунуті техніки","\u002Ftools\u002Fdocker\u002Fdockerfile-advanced","07.tools\u002F01.docker\u002F09.dockerfile-advanced",{"title":2931,"path":2932,"stem":2933},"Build Context та кешування шарів","\u002Ftools\u002Fdocker\u002Fbuild-context-and-cache","07.tools\u002F01.docker\u002F10.build-context-and-cache",{"title":2935,"path":2936,"stem":2937},"Реєстри Docker-образів","\u002Ftools\u002Fdocker\u002Fimage-registries","07.tools\u002F01.docker\u002F11.image-registries",{"title":2939,"path":2940,"stem":2941},"Контейнеризація .NET додатків","\u002Ftools\u002Fdocker\u002Fdotnet-containerization","07.tools\u002F01.docker\u002F12.dotnet-containerization",{"title":2943,"path":2944,"stem":2945},"Томи та збереження даних","\u002Ftools\u002Fdocker\u002Fvolumes-and-data","07.tools\u002F01.docker\u002F13.volumes-and-data",{"title":2947,"path":2948,"stem":2949},"Основи мережі в Docker","\u002Ftools\u002Fdocker\u002Fnetworking-basics","07.tools\u002F01.docker\u002F14.networking-basics",{"title":2951,"path":2952,"stem":2953},"Змінні оточення та конфігурація","\u002Ftools\u002Fdocker\u002Fenvironment-and-configuration","07.tools\u002F01.docker\u002F15.environment-and-configuration",{"title":2955,"path":2956,"stem":2957},"Docker Compose — оркестрація контейнерів","\u002Ftools\u002Fdocker\u002Fdocker-compose-basics","07.tools\u002F01.docker\u002F16.docker-compose-basics",{"title":2959,"path":2960,"stem":2961},"Docker Compose — Multi-Service застосунки","\u002Ftools\u002Fdocker\u002Fcompose-multi-service","07.tools\u002F01.docker\u002F17.compose-multi-service",{"title":2963,"icon":2964,"path":2965,"stem":2966,"children":2967},"Kubernetes","simple-icons:kubernetes","\u002Ftools\u002Fkubernetes","07.tools\u002F02.kubernetes\u002Findex",[2968,2970,2974,2978,2982,2986,2990,2994,2998],{"title":2969,"path":2965,"stem":2966},"Kubernetes: від розробки до production",{"title":2971,"path":2972,"stem":2973},"Kubernetes — коли Docker Compose більше не вистачає","\u002Ftools\u002Fkubernetes\u002Fwhy-kubernetes","07.tools\u002F02.kubernetes\u002F01.why-kubernetes",{"title":2975,"path":2976,"stem":2977},"Архітектура Kubernetes — анатомія кластера","\u002Ftools\u002Fkubernetes\u002Fkubernetes-architecture","07.tools\u002F02.kubernetes\u002F02.kubernetes-architecture",{"title":2979,"path":2980,"stem":2981},"Локальне середовище — minikube, kind та k3s","\u002Ftools\u002Fkubernetes\u002Flocal-environment","07.tools\u002F02.kubernetes\u002F03.local-environment",{"title":2983,"path":2984,"stem":2985},"Pod — атомарна одиниця Kubernetes","\u002Ftools\u002Fkubernetes\u002Fpods-and-containers","07.tools\u002F02.kubernetes\u002F04.pods-and-containers",{"title":2987,"path":2988,"stem":2989},"Патерни використання Pod","\u002Ftools\u002Fkubernetes\u002Fpod-patterns","07.tools\u002F02.kubernetes\u002F05.pod-patterns",{"title":2991,"path":2992,"stem":2993},"Deployment — декларативне управління Pod","\u002Ftools\u002Fkubernetes\u002Fdeployment-basics","07.tools\u002F02.kubernetes\u002F06.deployment-basics",{"title":2995,"path":2996,"stem":2997},"Rolling Updates та управління життєвим циклом Deployment","\u002Ftools\u002Fkubernetes\u002Fdeployment-rolling-updates","07.tools\u002F02.kubernetes\u002F07.deployment-rolling-updates",{"title":2999,"path":3000,"stem":3001},"Service — мережева абстракція для Pod","\u002Ftools\u002Fkubernetes\u002Fservices-networking","07.tools\u002F02.kubernetes\u002F08.services-networking",{"title":3003,"icon":3004,"path":3005,"stem":3006,"children":3007,"page":59},"Software Engineering","i-lucide-code-2","\u002Fsoftware-engineering","09.software-engineering",[3008,3012,3016,3020,3024,3028,3032,3036,3040,3044,3048],{"title":3009,"path":3010,"stem":3011},"1. Аналіз предметної області. Експертні знання та складність","\u002Fsoftware-engineering\u002Fintro-subdomains","09.software-engineering\u002F01.intro-subdomains",{"title":3013,"path":3014,"stem":3015},"2. Обмежені контексти. Інтеграція обмежених контекстів","\u002Fsoftware-engineering\u002Fintegrating-limited-contexts","09.software-engineering\u002F02.integrating-limited-contexts",{"title":3017,"path":3018,"stem":3019},"3. Реалізація простої бізнес-логіки","\u002Fsoftware-engineering\u002Fsimple","09.software-engineering\u002F03.simple",{"title":3021,"path":3022,"stem":3023},"4. Опрацювання складної бізнес-логіки","\u002Fsoftware-engineering\u002Fcomplex-business-logic","09.software-engineering\u002F04.complex-business-logic",{"title":3025,"path":3026,"stem":3027},"5. Моделювання фактора часу. Подієво-орієнтована архітектура.","\u002Fsoftware-engineering\u002Fmodelling-the-time-factor","09.software-engineering\u002F05.modelling-the-time-factor",{"title":3029,"path":3030,"stem":3031},"6. Архітектурні патерни","\u002Fsoftware-engineering\u002Farchitectural-patterns","09.software-engineering\u002F06.architectural-patterns",{"title":3033,"path":3034,"stem":3035},"Паттерни взаємодії","\u002Fsoftware-engineering\u002Fpatterns-of-interaction","09.software-engineering\u002F07.patterns-of-interaction",{"title":3037,"path":3038,"stem":3039},"Евристика проєктування","\u002Fsoftware-engineering\u002Fdesign-heuristics","09.software-engineering\u002F08.design-heuristics",{"title":3041,"path":3042,"stem":3043},"Еволюція проєктних рішень","\u002Fsoftware-engineering\u002Fevolution-of-design-solutions","09.software-engineering\u002F09.evolution-of-design-solutions",{"title":3045,"path":3046,"stem":3047},"EventStorming","\u002Fsoftware-engineering\u002Feventstorming","09.software-engineering\u002F10.eventstorming",{"title":3049,"path":3050,"stem":3051},"DDD на практиці","\u002Fsoftware-engineering\u002Fddd-in-practice","09.software-engineering\u002F11.ddd-in-practice",{"title":3053,"icon":943,"path":3054,"stem":3055,"children":3056,"page":59},"DDD","\u002Fddd","10.ddd",[3057,3061,3065,3069,3073,3077,3081,3085,3089,3093,3097,3101,3105],{"title":3058,"path":3059,"stem":3060},"Аналіз предметної області","\u002Fddd\u002Fdomain-analysis","10.ddd\u002F01.domain-analysis",{"title":3062,"path":3063,"stem":3064},"Експертні знання про предметну область","\u002Fddd\u002Fdomain-expert-knowledge","10.ddd\u002F02.domain-expert-knowledge",{"title":3066,"path":3067,"stem":3068},"Як осмислити складність предметної області","\u002Fddd\u002Fmanaging-domain-complexity","10.ddd\u002F03.managing-domain-complexity",{"title":3070,"path":3071,"stem":3072},"Інтеграція обмежених контекстів","\u002Fddd\u002Fbounded-context-integration","10.ddd\u002F04.bounded-context-integration",{"title":3074,"path":3075,"stem":3076},"Реалізація простої бізнес-логіки","\u002Fddd\u002Fsimple-business-logic","10.ddd\u002F05.simple-business-logic",{"title":3078,"path":3079,"stem":3080},"Обробка складної бізнес-логіки","\u002Fddd\u002Fcomplex-business-logic","10.ddd\u002F06.complex-business-logic",{"title":3082,"path":3083,"stem":3084},"Моделювання фактора часу","\u002Fddd\u002Ftime-modeling","10.ddd\u002F07.time-modeling",{"title":3086,"path":3087,"stem":3088},"Глава 8. Архітектурні Патерни","\u002Fddd\u002Farchitectural-patterns","10.ddd\u002F08.architectural-patterns",{"title":3090,"path":3091,"stem":3092},"Глава 9. Патерни Взаємодії","\u002Fddd\u002Finteraction-patterns","10.ddd\u002F09.interaction-patterns",{"title":3094,"path":3095,"stem":3096},"Глава 10. Проектні Евристики","\u002Fddd\u002Fdesign-heuristics","10.ddd\u002F10.design-heuristics",{"title":3098,"path":3099,"stem":3100},"Глава 11. Еволюція Проектних Рішень","\u002Fddd\u002Fevolution-of-design-decisions","10.ddd\u002F11.evolution-of-design-decisions",{"title":3102,"path":3103,"stem":3104},"Глава 12. EventStorming","\u002Fddd\u002Fevent-storming","10.ddd\u002F12.event-storming",{"title":3106,"path":3107,"stem":3108},"Глава 13. DDD на Практиці","\u002Fddd\u002Fddd-in-practice","10.ddd\u002F13.ddd-in-practice",{"title":3110,"icon":3111,"path":3112,"stem":3113,"children":3114,"page":59},"Media Streaming","i-lucide-video","\u002Fmedia-streaming","11.media-streaming",[3115,3119,3123,3127,3131,3135,3139],{"title":3116,"path":3117,"stem":3118},"01. Магія Стрімінгу: Що відбувається, коли ви натискаєте \"Play\"","\u002Fmedia-streaming\u002Fintroduction","11.media-streaming\u002F01.introduction",{"title":3120,"path":3121,"stem":3122},"02. Анатомія Медіа: Кодеки, Контейнери та Стиснення","\u002Fmedia-streaming\u002Faudio-video-anatomy","11.media-streaming\u002F02.audio-video-anatomy",{"title":3124,"path":3125,"stem":3126},"03. The Gym: FFmpeg Deep Dive","\u002Fmedia-streaming\u002Fffmpeg-gym","11.media-streaming\u002F03.ffmpeg-gym",{"title":3128,"path":3129,"stem":3130},"04. HLS Protocol: HTTP Live Streaming у Деталях","\u002Fmedia-streaming\u002Fhls-protocol","11.media-streaming\u002F04.hls-protocol",{"title":3132,"path":3133,"stem":3134},"05. DASH Protocol: Відкритий Стандарт","\u002Fmedia-streaming\u002Fdash-protocol","11.media-streaming\u002F05.dash-protocol",{"title":3136,"path":3137,"stem":3138},"06. Масштабування: CDN та Adaptive Bitrate","\u002Fmedia-streaming\u002Fcdn-and-adaptive-bitrate","11.media-streaming\u002F06.cdn-and-adaptive-bitrate",{"title":3140,"path":3141,"stem":3142},"07. Війна із Затримкою (Latency)","\u002Fmedia-streaming\u002Frealtime-latency","11.media-streaming\u002F07.realtime-latency",{"title":3144,"icon":3145,"path":3146,"stem":3147,"children":3148,"page":59},"HTML & CSS","i-devicon-html5","\u002Fhtml-css","12.html-css",[3149,3153,3157,3161,3165,3169,3173,3177,3181,3185,3189,3193,3197,3201,3205,3209,3213,3217,3221,3225,3229,3233,3237,3241,3245,3249,3253,3257,3261,3265],{"title":3150,"path":3151,"stem":3152},"Вступ до HTML. Структура документа","\u002Fhtml-css\u002Fintro-html-structure","12.html-css\u002F01.intro-html-structure",{"title":3154,"path":3155,"stem":3156},"Форматування тексту в HTML","\u002Fhtml-css\u002Fhtml-text-formatting","12.html-css\u002F02.html-text-formatting",{"title":3158,"path":3159,"stem":3160},"Посилання та зображення в HTML","\u002Fhtml-css\u002Fhtml-links-images","12.html-css\u002F03.html-links-images",{"title":3162,"path":3163,"stem":3164},"Списки та таблиці в HTML","\u002Fhtml-css\u002Fhtml-lists-tables","12.html-css\u002F04.html-lists-tables",{"title":3166,"path":3167,"stem":3168},"Форми в HTML","\u002Fhtml-css\u002Fhtml-forms","12.html-css\u002F05.html-forms",{"title":3170,"path":3171,"stem":3172},"Семантичні елементи HTML5","\u002Fhtml-css\u002Fhtml-semantic-elements","12.html-css\u002F06.html-semantic-elements",{"title":3174,"path":3175,"stem":3176},"Мультимедіа та розширені елементи HTML","\u002Fhtml-css\u002Fhtml-multimedia-advanced","12.html-css\u002F07.html-multimedia-advanced",{"title":3178,"path":3179,"stem":3180},"Мікророзмітка та SEO в HTML","\u002Fhtml-css\u002Fhtml-microdata-seo","12.html-css\u002F08.html-microdata-seo",{"title":3182,"path":3183,"stem":3184},"Вступ до CSS. Селектори та специфічність","\u002Fhtml-css\u002Fcss-intro-selectors","12.html-css\u002F09.css-intro-selectors",{"title":3186,"path":3187,"stem":3188},"Блокова модель CSS. Відступи. Box Sizing","\u002Fhtml-css\u002Fcss-box-model","12.html-css\u002F10.css-box-model",{"title":3190,"path":3191,"stem":3192},"Розміри у CSS: повний довідник одиниць і ключових слів","\u002Fhtml-css\u002F10a.css-sizing","12.html-css\u002F10a.css-sizing",{"title":3194,"path":3195,"stem":3196},"Типографіка в CSS. Шрифти та текст","\u002Fhtml-css\u002Fcss-typography","12.html-css\u002F11.css-typography",{"title":3198,"path":3199,"stem":3200},"Кольори та фони в CSS","\u002Fhtml-css\u002Fcss-colors-backgrounds","12.html-css\u002F12.css-colors-backgrounds",{"title":3202,"path":3203,"stem":3204},"Тіні та фільтри в CSS","\u002Fhtml-css\u002F12b.css-shadows-filters","12.html-css\u002F12b.css-shadows-filters",{"title":3206,"path":3207,"stem":3208},"CSS Flexbox: Фундамент гнучких макетів","\u002Fhtml-css\u002Fcss-flexbox-fundamentals","12.html-css\u002F13.css-flexbox-fundamentals",{"title":3210,"path":3211,"stem":3212},"CSS Flexbox: Вирівнювання та Позиціонування","\u002Fhtml-css\u002Fcss-flexbox-alignment-sizing-and-patterns","12.html-css\u002F14.css-flexbox-alignment-sizing-and-patterns",{"title":3214,"path":3215,"stem":3216},"CSS Grid. Двовимірний макет. Частина 1","\u002Fhtml-css\u002Fcss-layout-grid","12.html-css\u002F15.css-layout-grid",{"title":3218,"path":3219,"stem":3220},"CSS Grid. Двовимірний макет. Частина 2","\u002Fhtml-css\u002Fcss-layout-grid-advanced","12.html-css\u002F16.css-layout-grid-advanced",{"title":3222,"path":3223,"stem":3224},"Позиціонування в CSS. Z-index. Stacking Context","\u002Fhtml-css\u002Fcss-positioning","12.html-css\u002F17.css-positioning",{"title":3226,"path":3227,"stem":3228},"CSS Анімації та Переходи","\u002Fhtml-css\u002Fcss-animations-transitions","12.html-css\u002F18.css-animations-transitions",{"title":3230,"path":3231,"stem":3232},"Адаптивний дизайн. Media Queries. Частина 1","\u002Fhtml-css\u002Fcss-responsive-media-queries","12.html-css\u002F19.css-responsive-media-queries",{"title":3234,"path":3235,"stem":3236},"Адаптивний дизайн. Частина 2: clamp(), Container Queries, @layer","\u002Fhtml-css\u002Fcss-responsive-advanced","12.html-css\u002F20.css-responsive-advanced",{"title":3238,"path":3239,"stem":3240},"CSS Custom Properties. Методології. Сучасний CSS","\u002Fhtml-css\u002Fcss-variables-methodologies","12.html-css\u002F21.css-variables-methodologies",{"title":3242,"path":3243,"stem":3244},"Сучасний CSS 2023–2025: Нові можливості","\u002Fhtml-css\u002Fcss-modern-features","12.html-css\u002F22.css-modern-features",{"title":3246,"path":3247,"stem":3248},"CSS Nesting, @layer, @scope та @property: нативний препроцесор","\u002Fhtml-css\u002F22a.css-nesting-modern-syntax","12.html-css\u002F22a.css-nesting-modern-syntax",{"title":3250,"path":3251,"stem":3252},"CSS для форм та інтерактивних станів","\u002Fhtml-css\u002Fcss-forms-interactive-states","12.html-css\u002F23.css-forms-interactive-states",{"title":3254,"path":3255,"stem":3256},"Доступність у CSS (CSS Accessibility)","\u002Fhtml-css\u002Fcss-accessibility","12.html-css\u002F24.css-accessibility",{"title":3258,"path":3259,"stem":3260},"CSS-функції та сучасні sizing primitives","\u002Fhtml-css\u002Fcss-functions-sizing","12.html-css\u002F25.css-functions-sizing",{"title":3262,"path":3263,"stem":3264},"Rendering Pipeline і CSS Performance","\u002Fhtml-css\u002Fcss-rendering-performance","12.html-css\u002F26.css-rendering-performance",{"title":3266,"path":3267,"stem":3268},"CSS Best Practices: типові ситуації та правильні рішення","\u002Fhtml-css\u002Fcss-best-practices","12.html-css\u002F27.css-best-practices",{"title":3270,"path":3271,"stem":3272,"children":3273,"page":59},"AWS","\u002Faws","13.aws",[3274,3278,3282,3286,3290,3294,3298,3302,3306,3310,3314,3318,3322,3326,3330,3334,3338,3342],{"title":3275,"path":3276,"stem":3277},"Реєстрація AWS акаунту та студентські програми","\u002Faws\u002Faccount-registration","13.aws\u002F00.account-registration",{"title":3279,"path":3280,"stem":3281},"Вступ до хмарних обчислень та AWS","\u002Faws\u002Fintroduction-to-cloud","13.aws\u002F01.introduction-to-cloud",{"title":3283,"path":3284,"stem":3285},"AWS IAM — Identity and Access Management","\u002Faws\u002Fiam","13.aws\u002F02.iam",{"title":3287,"path":3288,"stem":3289},"AWS IAM CLI — Довідник команд","\u002Faws\u002F02a.iam-doc","13.aws\u002F02a.iam-doc",{"title":3291,"path":3292,"stem":3293},"Docker та контейнеризація в AWS — ECR, ECS та Fargate","\u002Faws\u002Fdocker-ecs","13.aws\u002F03.docker-ecs",{"title":3295,"path":3296,"stem":3297},"AWS ECR \u002F ECS CLI — Довідник команд","\u002Faws\u002F03a.docker-ecs-doc","13.aws\u002F03a.docker-ecs-doc",{"title":3299,"path":3300,"stem":3301},"Amazon EC2 — Elastic Compute Cloud","\u002Faws\u002Fec2","13.aws\u002F04.ec2",{"title":3303,"path":3304,"stem":3305},"AWS EC2 CLI — Довідник команд","\u002Faws\u002F04a.ec2-doc","13.aws\u002F04a.ec2-doc",{"title":3307,"path":3308,"stem":3309},"Elastic Load Balancing та Auto Scaling","\u002Faws\u002Falb-asg","13.aws\u002F05.alb-asg",{"title":3311,"path":3312,"stem":3313},"Amazon S3 — Simple Storage Service","\u002Faws\u002Fs3","13.aws\u002F06.s3",{"title":3315,"path":3316,"stem":3317},"Amazon CloudFront — Content Delivery Network","\u002Faws\u002Fcloudfront","13.aws\u002F07.cloudfront",{"title":3319,"path":3320,"stem":3321},"Amazon RDS — Relational Database Service","\u002Faws\u002Frds","13.aws\u002F08.rds",{"title":3323,"path":3324,"stem":3325},"Amazon DynamoDB — NoSQL Database","\u002Faws\u002Fdynamodb","13.aws\u002F09.dynamodb",{"title":3327,"path":3328,"stem":3329},"AWS Lambda та Serverless Compute","\u002Faws\u002Flambda","13.aws\u002F10.lambda",{"title":3331,"path":3332,"stem":3333},"Amazon Bedrock - Foundation Models, RAG та Agents","\u002Faws\u002Fbedrock","13.aws\u002F22.bedrock",{"title":3335,"path":3336,"stem":3337},"Amazon Rekognition - Комп'ютерний зір","\u002Faws\u002Frekognition","13.aws\u002F23.rekognition",{"title":3339,"path":3340,"stem":3341},"Amazon Textract - Інтелектуальний аналіз документів","\u002Faws\u002Ftextract","13.aws\u002F24.textract",{"title":3343,"path":3344,"stem":3345},"Amazon Polly, Transcribe, Comprehend та Translate","\u002Faws\u002Faudio-nlp-services","13.aws\u002F25.audio-nlp-services",{"title":3347,"path":3348,"stem":3349,"children":3350,"page":59},"Ai Development","\u002Fai-development","14.ai-development",[3351],{"title":3352,"path":3353,"stem":3354,"children":3355,"page":59},"Foundations","\u002Fai-development\u002Ffoundations","14.ai-development\u002F00.foundations",[3356],{"title":3357,"path":3358,"stem":3359},"Модуль 0.1. Що таке Large Language Model (LLM)","\u002Fai-development\u002Ffoundations\u002Fwhat-is-llm","14.ai-development\u002F00.foundations\u002F01.what-is-llm",{"title":3361,"path":3362,"stem":3363,"children":3364,"page":59},"React Native","\u002Freact-native","15.react-native",[3365,3386],{"title":3366,"path":3367,"stem":3368,"children":3369,"page":59},"Version1","\u002Freact-native\u002Fversion1","15.react-native\u002Fversion1",[3370,3374,3378,3382],{"title":3371,"path":3372,"stem":3373},"Що таке React Native","\u002Freact-native\u002Fversion1\u002Fwhat-is-react-native","15.react-native\u002Fversion1\u002F01.what-is-react-native",{"title":3375,"path":3376,"stem":3377},"Як влаштований React Native «під капотом»","\u002Freact-native\u002Fversion1\u002Freact-native-architecture","15.react-native\u002Fversion1\u002F02.react-native-architecture",{"title":3379,"path":3380,"stem":3381},"Від React до React Native: ключові відмінності","\u002Freact-native\u002Fversion1\u002Freact-native-vs-react","15.react-native\u002Fversion1\u002F03.react-native-vs-react",{"title":3383,"path":3384,"stem":3385},"View та Text — фундаментальні будівельні блоки","\u002Freact-native\u002Fversion1\u002Fview-and-text","15.react-native\u002Fversion1\u002F04.view-and-text",{"title":3387,"path":3388,"stem":3389,"children":3390,"page":59},"Version2","\u002Freact-native\u002Fversion2","15.react-native\u002Fversion2",[3391,3395,3399,3403,3407,3411,3415,3419,3423,3427,3431,3435,3439,3443,3447,3451,3455,3459,3463,3467,3471,3475,3479,3483,3487,3491],{"title":3392,"path":3393,"stem":3394},"React Native — навіщо він потрібен","\u002Freact-native\u002Fversion2\u002Fwhy-react-native","15.react-native\u002Fversion2\u002F01.why-react-native",{"title":3396,"path":3397,"stem":3398},"Налаштування середовища розробки","\u002Freact-native\u002Fversion2\u002Fenvironment-setup","15.react-native\u002Fversion2\u002F02.environment-setup",{"title":3400,"path":3401,"stem":3402},"Expo і класичний React Native — два шляхи одного фреймворку","\u002Freact-native\u002Fversion2\u002Fexpo-vs-cli-landscape","15.react-native\u002Fversion2\u002F03.expo-vs-cli-landscape",{"title":3404,"path":3405,"stem":3406},"Середовище Expo — перший запуск","\u002Freact-native\u002Fversion2\u002Fexpo-setup-and-tooling","15.react-native\u002Fversion2\u002F04.expo-setup-and-tooling",{"title":3408,"path":3409,"stem":3410},"Структура проєкту та перші UI-примітиви","\u002Freact-native\u002Fversion2\u002Fproject-structure-and-conventions","15.react-native\u002Fversion2\u002F05.project-structure-and-conventions",{"title":3412,"path":3413,"stem":3414},"Базові компоненти React Native","\u002Freact-native\u002Fversion2\u002Fcore-components","15.react-native\u002Fversion2\u002F06.core-components",{"title":3416,"path":3417,"stem":3418},"Flexbox і layout у React Native","\u002Freact-native\u002Fversion2\u002Fflexbox-and-layout","15.react-native\u002Fversion2\u002F07.flexbox-and-layout",{"title":3420,"path":3421,"stem":3422},"StyleSheet і теми (light \u002F dark)","\u002Freact-native\u002Fversion2\u002Fstylesheet-and-theming","15.react-native\u002Fversion2\u002F08.stylesheet-and-theming",{"title":3424,"path":3425,"stem":3426},"Списки та віртуалізація","\u002Freact-native\u002Fversion2\u002Flists-and-virtualization","15.react-native\u002Fversion2\u002F09.lists-and-virtualization",{"title":3428,"path":3429,"stem":3430},"Форми, ввід і валідація","\u002Freact-native\u002Fversion2\u002Fforms-input-validation","15.react-native\u002Fversion2\u002F10.forms-input-validation",{"title":3432,"path":3433,"stem":3434},"Основи Expo Router","\u002Freact-native\u002Fversion2\u002Fexpo-router-basics","15.react-native\u002Fversion2\u002F11.expo-router-basics",{"title":3436,"path":3437,"stem":3438},"Вкладені навігатори та модалки","\u002Freact-native\u002Fversion2\u002Fnested-navigators-and-modals","15.react-native\u002Fversion2\u002F12.nested-navigators-and-modals",{"title":3440,"path":3441,"stem":3442},"Deep linking і параметри маршрутів","\u002Freact-native\u002Fversion2\u002Fdeep-linking-and-params","15.react-native\u002Fversion2\u002F13.deep-linking-and-params",{"title":3444,"path":3445,"stem":3446},"Робота з мережею та життєвий цикл застосунку","\u002Freact-native\u002Fversion2\u002Fnetworking-and-app-lifecycle","15.react-native\u002Fversion2\u002F14.networking-and-app-lifecycle",{"title":3448,"path":3449,"stem":3450},"Redux Toolkit на мобільних платформах","\u002Freact-native\u002Fversion2\u002Fredux-toolkit-on-mobile","15.react-native\u002Fversion2\u002F15.redux-toolkit-on-mobile",{"title":3452,"path":3453,"stem":3454},"RTK Query на мобільних платформах","\u002Freact-native\u002Fversion2\u002Frtk-query-mobile","15.react-native\u002Fversion2\u002F16.rtk-query-mobile",{"title":3456,"path":3457,"stem":3458},"Автентифікація та Безпечне Зберігання","\u002Freact-native\u002Fversion2\u002Fauth-secure-storage","15.react-native\u002Fversion2\u002F18.auth-secure-storage",{"title":3460,"path":3461,"stem":3462},"Локальне сховище — AsyncStorage, MMKV, SQLite","\u002Freact-native\u002Fversion2\u002Flocal-storage-mmkv-sqlite","15.react-native\u002Fversion2\u002F19.local-storage-mmkv-sqlite",{"title":3464,"path":3465,"stem":3466},"Офлайн-First і синхронізація","\u002Freact-native\u002Fversion2\u002Foffline-first-sync","15.react-native\u002Fversion2\u002F20.offline-first-sync",{"title":3468,"path":3469,"stem":3470},"Камера, медіа та файлова система","\u002Freact-native\u002Fversion2\u002Fcamera-media-filesystem","15.react-native\u002Fversion2\u002F21.camera-media-filesystem",{"title":3472,"path":3473,"stem":3474},"Карти та геолокація","\u002Freact-native\u002Fversion2\u002Fmaps-and-location","15.react-native\u002Fversion2\u002F22.maps-and-location",{"title":3476,"path":3477,"stem":3478},"Жести та дотики","\u002Freact-native\u002Fversion2\u002Fgestures-and-touch","15.react-native\u002Fversion2\u002F23.gestures-and-touch",{"title":3480,"path":3481,"stem":3482},"Анімації з Reanimated","\u002Freact-native\u002Fversion2\u002Freanimated-animations","15.react-native\u002Fversion2\u002F24.reanimated-animations",{"title":3484,"path":3485,"stem":3486},"Push і локальні сповіщення","\u002Freact-native\u002Fversion2\u002Fpush-and-local-notifications","15.react-native\u002Fversion2\u002F25.push-and-local-notifications",{"title":3488,"path":3489,"stem":3490},"Доступність та інтернаціоналізація","\u002Freact-native\u002Fversion2\u002Faccessibility-and-i18n","15.react-native\u002Fversion2\u002F26.accessibility-and-i18n",{"title":3492,"path":3493,"stem":3494},"EAS Build та профілі збірки","\u002Freact-native\u002Fversion2\u002Feas-build-and-profiles","15.react-native\u002Fversion2\u002F29.eas-build-and-profiles",{"title":3496,"path":3497,"stem":3498,"children":3499,"page":59},"Ai Python","\u002Fai-python","16.ai-python",[3500,3504,3508],{"title":3501,"path":3502,"stem":3503},"Вступ до штучного інтелекту та машинного навчання","\u002Fai-python\u002Fintro-to-ai","16.ai-python\u002F01.intro-to-ai",{"title":3505,"path":3506,"stem":3507},"Знайомство з Jupyter Notebook та JupyterLab","\u002Fai-python\u002Fjupyter-notebook","16.ai-python\u002F02.jupyter-notebook",{"title":3509,"path":3510,"stem":3511},"Робота з даними з використанням NumPy і pandas","\u002Fai-python\u002Fnumpy-pandas","16.ai-python\u002F03.numpy-pandas",{"title":3513,"icon":658,"path":3514,"stem":3515,"children":3516,"page":59},"Клієнт-серверна архітектура","\u002Fclient-server-architecture","17.client-server-architecture",[3517,3521],{"title":3518,"path":3519,"stem":3520},"Архітектура клієнт-серверних систем та основи Go","\u002Fclient-server-architecture\u002Fclient-server-architecture-and-go","17.client-server-architecture\u002F01.client-server-architecture-and-go",{"title":3522,"path":3523,"stem":3524},"Система типів та модель пам’яті мови Go","\u002Fclient-server-architecture\u002Ftype-system-and-memory-model","17.client-server-architecture\u002F02.type-system-and-memory-model",{"title":3526,"icon":1946,"path":3527,"stem":3528,"children":3529,"page":59},"Розробка WEB-застосувань","\u002Fweb-development","18.web-development",[3530,3575,3613,3642],{"title":3531,"icon":658,"path":3532,"stem":3533,"children":3534,"page":59},"Архітектура комп'ютерних мереж та мережеві протоколи","\u002Fweb-development\u002Fnetwork-architecture-and-protocols","18.web-development\u002F01.network-architecture-and-protocols",[3535,3539,3543,3547,3551,3555,3559,3563,3567,3571],{"title":3536,"path":3537,"stem":3538},"Еволюція веброзробки та модель клієнт-сервер","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fweb-evolution-client-server","18.web-development\u002F01.network-architecture-and-protocols\u002F01.web-evolution-client-server",{"title":3540,"path":3541,"stem":3542},"Еталонна модель OSI","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fosi-model","18.web-development\u002F01.network-architecture-and-protocols\u002F02.osi-model",{"title":3544,"path":3545,"stem":3546},"Стек протоколів TCP\u002FIP","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Ftcp-ip-stack","18.web-development\u002F01.network-architecture-and-protocols\u002F03.tcp-ip-stack",{"title":3548,"path":3549,"stem":3550},"IP-адресація, порти та сокети","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fip-addressing-ports-sockets","18.web-development\u002F01.network-architecture-and-protocols\u002F04.ip-addressing-ports-sockets",{"title":3552,"path":3553,"stem":3554},"Протоколи TCP та UDP","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Ftcp-udp-protocols","18.web-development\u002F01.network-architecture-and-protocols\u002F05.tcp-udp-protocols",{"title":3556,"path":3557,"stem":3558},"Система доменних імен DNS","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fdns-system","18.web-development\u002F01.network-architecture-and-protocols\u002F06.dns-system",{"title":3560,"path":3561,"stem":3562},"Протокол SMTP та поштові протоколи","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fsmtp-email-protocols","18.web-development\u002F01.network-architecture-and-protocols\u002F07.smtp-email-protocols",{"title":3564,"path":3565,"stem":3566},"Протокол WebSocket","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fwebsocket-protocol","18.web-development\u002F01.network-architecture-and-protocols\u002F08.websocket-protocol",{"title":3568,"path":3569,"stem":3570},"Протокол SSH","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fssh-protocol","18.web-development\u002F01.network-architecture-and-protocols\u002F09.ssh-protocol",{"title":3572,"path":3573,"stem":3574},"Огляд сучасних серверних технологій","\u002Fweb-development\u002Fnetwork-architecture-and-protocols\u002Fmodern-backend-technologies","18.web-development\u002F01.network-architecture-and-protocols\u002F10.modern-backend-technologies",{"title":3576,"icon":3577,"path":3578,"stem":3579,"children":3580,"page":59},"Протокол HTTP та захищена передача даних HTTPS","i-lucide-lock","\u002Fweb-development\u002Fhttp-and-https","18.web-development\u002F02.http-and-https",[3581,3585,3589,3593,3597,3601,3605,3609],{"title":3582,"path":3583,"stem":3584},"Вступ до протоколу HTTP та еволюція веб-технологій","\u002Fweb-development\u002Fhttp-and-https\u002Fintroduction-and-evolution","18.web-development\u002F02.http-and-https\u002F01.introduction-and-evolution",{"title":3586,"path":3587,"stem":3588},"Анатомія HTTP-запиту","\u002Fweb-development\u002Fhttp-and-https\u002Fhttp-request-structure","18.web-development\u002F02.http-and-https\u002F02.http-request-structure",{"title":3590,"path":3591,"stem":3592},"Анатомія HTTP-відповіді","\u002Fweb-development\u002Fhttp-and-https\u002Fhttp-response-structure","18.web-development\u002F02.http-and-https\u002F03.http-response-structure",{"title":3594,"path":3595,"stem":3596},"Методи HTTP та їхня семантика","\u002Fweb-development\u002Fhttp-and-https\u002Fhttp-methods","18.web-development\u002F02.http-and-https\u002F04.http-methods",{"title":3598,"path":3599,"stem":3600},"Коди статусу HTTP та їхнє призначення","\u002Fweb-development\u002Fhttp-and-https\u002Fhttp-status-codes","18.web-development\u002F02.http-and-https\u002F05.http-status-codes",{"title":3602,"path":3603,"stem":3604},"HTTP-заголовки та їхнє призначення","\u002Fweb-development\u002Fhttp-and-https\u002Fhttp-headers","18.web-development\u002F02.http-and-https\u002F06.http-headers",{"title":3606,"path":3607,"stem":3608},"CORS та механізми безпеки HTTP","\u002Fweb-development\u002Fhttp-and-https\u002Fcors-and-security","18.web-development\u002F02.http-and-https\u002F07.cors-and-security",{"title":3610,"path":3611,"stem":3612},"HTTPS та криптографічні основи TLS","\u002Fweb-development\u002Fhttp-and-https\u002Fhttps-and-tls","18.web-development\u002F02.http-and-https\u002F08.https-and-tls",{"title":3614,"icon":2326,"path":3615,"stem":3616,"children":3617,"page":59},"Система типів мови TypeScript","\u002Fweb-development\u002Ftypescript-type-system","18.web-development\u002F03.typescript-type-system",[3618,3622,3626,3630,3634,3638],{"title":3619,"path":3620,"stem":3621},"Знайомство з TypeScript Compiler","\u002Fweb-development\u002Ftypescript-type-system\u002Fintroduction-compiler-config","18.web-development\u002F03.typescript-type-system\u002F01.introduction-compiler-config",{"title":3623,"path":3624,"stem":3625},"Примітивні типи даних: string, number, boolean","\u002Fweb-development\u002Ftypescript-type-system\u002Fprimitive-special-types","18.web-development\u002F03.typescript-type-system\u002F02.primitive-special-types",{"title":3627,"path":3628,"stem":3629},"Масиви, кортежі та об","\u002Fweb-development\u002Ftypescript-type-system\u002Farrays-tuples-objects","18.web-development\u002F03.typescript-type-system\u002F03.arrays-tuples-objects",{"title":3631,"path":3632,"stem":3633},"Union типи, Intersection типи та літеральні типи","\u002Fweb-development\u002Ftypescript-type-system\u002Funion-intersection-literals","18.web-development\u002F03.typescript-type-system\u002F04.union-intersection-literals",{"title":3635,"path":3636,"stem":3637},"Type Narrowing (звуження типів)","\u002Fweb-development\u002Ftypescript-type-system\u002Ftype-narrowing","18.web-development\u002F03.typescript-type-system\u002F05.type-narrowing",{"title":3639,"path":3640,"stem":3641},"Типізація функцій","\u002Fweb-development\u002Ftypescript-type-system\u002Ffunctions-typing","18.web-development\u002F03.typescript-type-system\u002F06.functions-typing",{"title":3643,"icon":2326,"path":3644,"stem":3645,"children":3646,"page":59},"Розширені засоби мови TypeScript","\u002Fweb-development\u002Ftypescript-advanced","18.web-development\u002F04.typescript-advanced",[3647,3651,3655,3659,3663,3667],{"title":3648,"path":3649,"stem":3650},"Interfaces та Classes","\u002Fweb-development\u002Ftypescript-advanced\u002Finterfaces-classes","18.web-development\u002F04.typescript-advanced\u002F01.interfaces-classes",{"title":3652,"path":3653,"stem":3654},"Основи Generic типів","\u002Fweb-development\u002Ftypescript-advanced\u002Fgenerics-fundamentals","18.web-development\u002F04.typescript-advanced\u002F02.generics-fundamentals",{"title":3656,"path":3657,"stem":3658},"Enums та Decorators","\u002Fweb-development\u002Ftypescript-advanced\u002Fenums-decorators","18.web-development\u002F04.typescript-advanced\u002F03.enums-decorators",{"title":3660,"path":3661,"stem":3662},"Utility Types","\u002Fweb-development\u002Ftypescript-advanced\u002Futility-types","18.web-development\u002F04.typescript-advanced\u002F04.utility-types",{"title":3664,"path":3665,"stem":3666},"Mapped та Conditional Types","\u002Fweb-development\u002Ftypescript-advanced\u002Fmapped-conditional-types","18.web-development\u002F04.typescript-advanced\u002F05.mapped-conditional-types",{"title":3668,"path":3669,"stem":3670},"Модулі та Strict Mode","\u002Fweb-development\u002Ftypescript-advanced\u002Fmodules-strict-mode","18.web-development\u002F04.typescript-advanced\u002F06.modules-strict-mode",{"title":3672,"path":3673,"stem":3674,"children":3675,"page":59},"Tailwind","\u002Ftailwind","21.tailwind",[3676,3680,3684,3688,3692,3696,3700,3704,3708,3712,3716,3720],{"title":3677,"path":3678,"stem":3679},"Що таке Tailwind CSS і навіщо він потрібен","\u002Ftailwind\u002Ftailwind-intro-philosophy","21.tailwind\u002F01.tailwind-intro-philosophy",{"title":3681,"path":3682,"stem":3683},"Встановлення та налаштування Tailwind CSS v4","\u002Ftailwind\u002Ftailwind-installation-setup","21.tailwind\u002F02.tailwind-installation-setup",{"title":3685,"path":3686,"stem":3687},"Utility-класи: основи та система Tailwind","\u002Ftailwind\u002Ftailwind-utility-classes-core","21.tailwind\u002F03.tailwind-utility-classes-core",{"title":3689,"path":3690,"stem":3691},"Layout: Flexbox та Grid через Tailwind","\u002Ftailwind\u002Ftailwind-flexbox-grid","21.tailwind\u002F04.tailwind-flexbox-grid",{"title":3693,"path":3694,"stem":3695},"Кастомізація теми через @theme у Tailwind v4","\u002Ftailwind\u002Ftailwind-theme-customization","21.tailwind\u002F05.tailwind-theme-customization",{"title":3697,"path":3698,"stem":3699},"Варіанти: hover, focus, responsive, dark mode та нові v4","\u002Ftailwind\u002Ftailwind-variants-states","21.tailwind\u002F06.tailwind-variants-states",{"title":3701,"path":3702,"stem":3703},"Типографіка та система кольорів у Tailwind v4","\u002Ftailwind\u002Ftailwind-typography-colors","21.tailwind\u002F07.tailwind-typography-colors",{"title":3705,"path":3706,"stem":3707},"Компоненти та повторюваність: @apply, @utility та патерни","\u002Ftailwind\u002Ftailwind-components-patterns","21.tailwind\u002F08.tailwind-components-patterns",{"title":3709,"path":3710,"stem":3711},"Темна тема та система дизайн-токенів у Tailwind v4","\u002Ftailwind\u002Ftailwind-dark-mode-theming","21.tailwind\u002F09.tailwind-dark-mode-theming",{"title":3713,"path":3714,"stem":3715},"Довільні значення та контейнерні запити у Tailwind v4","\u002Ftailwind\u002Ftailwind-arbitrary-container-queries","21.tailwind\u002F10.tailwind-arbitrary-container-queries",{"title":3717,"path":3718,"stem":3719},"Анімації, трансформації та 3D у Tailwind v4","\u002Ftailwind\u002Ftailwind-animations-transforms","21.tailwind\u002F11.tailwind-animations-transforms",{"title":3721,"path":3722,"stem":3723},"Tailwind CLI, PostCSS та інтеграція з фреймворками","\u002Ftailwind\u002Ftailwind-cli-tooling","21.tailwind\u002F12.tailwind-cli-tooling",{"title":3725,"path":3726,"stem":3727},"Тестування компонентів діаграм","\u002Ftest-components","98.test-components",{"id":3729,"title":3464,"body":3730,"description":19845,"extension":19846,"links":19847,"meta":19848,"navigation":4831,"path":3465,"seo":19849,"stem":3466,"__hash__":19850},"docs\u002F15.react-native\u002Fversion2\u002F20.offline-first-sync.md",{"type":3731,"value":3732,"toc":19810},"minimark",[3733,3737,3742,3751,3758,3761,3805,3824,3835,3838,3842,3847,3858,3861,3921,3926,3953,3960,3962,3966,3972,4139,4144,4195,4200,4205,4229,4231,4235,4243,4302,4307,4365,4370,4420,4449,4451,4455,4461,4488,4493,4553,4573,4582,4587,4628,4638,4640,4644,4651,4656,4746,4751,4783,4793,4795,4799,4802,5039,5044,5171,5181,5183,5187,5196,5201,5423,5428,5677,5682,5838,5856,5858,5865,5879,5882,5885,5900,5905,5965,5970,6031,6050,6055,6580,6585,6605,6611,6616,6627,6711,6714,6716,6719,6725,6730,6924,6929,7037,7042,7062,7067,7081,7086,7107,7117,7125,7127,7131,7134,7252,7260,7265,7267,7271,7282,7287,7351,7361,7372,7374,7378,7385,7404,7409,7432,7437,10930,10932,10936,11165,11167,11171,11273,11287,11289,11293,11335,11337,11341,11345,11348,11355,11358,11364,11393,11395,11399,11403,11447,11451,11542,11544,11548,11555,19807],[3734,3735,3464],"h1",{"id":3736},"офлайн-first-і-синхронізація",[3738,3739,3741],"h2",{"id":3740},"відкриття-коли-мережі-немає-а-працювати-треба","Відкриття: коли мережі немає, а працювати треба",[3743,3744,3745,3746,3750],"p",{},"Уявіть: ви в метро, їдете на роботу, і вирішуєте додати нову поїздку до щоденника. Натискаєте «Створити», заповнюєте назву, дату — і лише тоді помічаєте: мережі немає. Вебсайт у цей момент показав би помилку «No connection» і попросив спробувати пізніше. Але мобільний застосунок може вчинити інакше: ",[3747,3748,3749],"strong",{},"зберегти вашу поїздку локально"," і відправити на сервер автоматично, коли з'явиться інтернет. Ви навіть не помітите проблеми — просто продовжуєте працювати.",[3743,3752,3753,3754,3757],{},"Такий підхід називають ",[3747,3755,3756],{},"офлайн-first"," (offline-first): застосунок спочатку зберігає дані локально на пристрої, а вже потім намагається синхронізувати їх із сервером. Користувач не чекає на мережу — він бачить свої зміни одразу, а застосунок у фоні «домовляється» з API.",[3743,3759,3760],{},"У попередній статті ми розглянули, як зберігати дані локально через MMKV і SQLite. Тепер з'ясуємо:",[3762,3763,3764,3772,3791,3798],"ul",{},[3765,3766,3767,3768,3771],"li",{},"Як ",[3747,3769,3770],{},"ставити зміни в чергу"," (outbox pattern), коли API недоступний.",[3765,3773,3774,3775,3778,3779,3783,3784,3783,3787,3790],{},"Як показувати ",[3747,3776,3777],{},"статус синхронізації"," (",[3780,3781,3782],"code",{},"pending",", ",[3780,3785,3786],{},"synced",[3780,3788,3789],{},"error",") на кожному record.",[3765,3792,3793,3794,3797],{},"Що робити з ",[3747,3795,3796],{},"конфліктами",", коли сервер повертає іншу версію даних.",[3765,3799,3800,3801,3804],{},"Як побудувати ",[3747,3802,3803],{},"UX для офлайн-режиму"," — banner «Офлайн», retry-кнопки, оптимістичні оновлення.",[3743,3806,3807,3808,3811,3812,3815,3816,3819,3820,3823],{},"Наприкінці статті ми напишемо ",[3747,3809,3810],{},"міні-проєкт «Офлайн-чеклист»"," — простий TODO-список, який додає завдання локально, ставить їх у чергу і синхронізує з mock API, коли з'являється мережа. Потім у ",[3747,3813,3814],{},"Nomad"," реалізуємо повноцінну систему синхронізації поїздок і місць з полями ",[3780,3817,3818],{},"syncStatus"," і ",[3780,3821,3822],{},"syncError",".",[3825,3826,3827,3830,3831,3834],"note",{},[3747,3828,3829],{},"Офлайн-first"," — це архітектура, де застосунок ",[3747,3832,3833],{},"завжди"," працює з локальною базою, а синхронізація з сервером відбувається у фоні. Користувач не блокується на час запиту — він бачить свої дані одразу, навіть якщо мережі немає.",[3836,3837],"hr",{},[3738,3839,3841],{"id":3840},"частина-1-теорія-офлайн-синхронізації","Частина 1. Теорія офлайн-синхронізації",[3843,3844,3846],"h3",{"id":3845},"_11-навіщо-офлайн-first-у-мобільних-застосунках","1.1. Навіщо офлайн-first у мобільних застосунках",[3743,3848,3849,3850,3853,3854,3857],{},"У веб-застосунках зазвичай діє модель ",[3747,3851,3852],{},"online-first",": користувач натискає «Зберегти», браузер робить POST-запит на сервер, і лише після відповіді ",[3780,3855,3856],{},"200 OK"," показується успіх. Якщо мережі немає або сервер недоступний — з'являється помилка, і користувач чекає.",[3743,3859,3860],{},"У мобільних застосунках цей підхід працює гірше через кілька причин:",[3862,3863,3864,3877],"table",{},[3865,3866,3867],"thead",{},[3868,3869,3870,3874],"tr",{},[3871,3872,3873],"th",{},"Причина",[3871,3875,3876],{},"Чому це важливо на телефоні",[3878,3879,3880,3891,3901,3911],"tbody",{},[3868,3881,3882,3888],{},[3883,3884,3885],"td",{},[3747,3886,3887],{},"Нестабільна мережа",[3883,3889,3890],{},"Користувач переміщується між Wi-Fi, LTE, метро, ліфтом — з'єднання може зникнути в будь-який момент.",[3868,3892,3893,3898],{},[3883,3894,3895],{},[3747,3896,3897],{},"Повільний інтернет",[3883,3899,3900],{},"У роумінгу або на околиці міста запит може йти кілька секунд — чекати на відповідь сервера дратує.",[3868,3902,3903,3908],{},[3883,3904,3905],{},[3747,3906,3907],{},"Батарея",[3883,3909,3910],{},"Синхронні запити тримають екран активним; фонова черга дозволяє об'єднати кілька операцій в один batch.",[3868,3912,3913,3918],{},[3883,3914,3915],{},[3747,3916,3917],{},"UX-очікування",[3883,3919,3920],{},"Користувачі звикли, що телефон «просто працює» — як у native-застосунках (Notes, Photos), які зберігають локально і синхронізують сховано.",[3743,3922,3923,3925],{},[3747,3924,3829],{}," вирішує ці проблеми:",[3927,3928,3929,3935,3941,3947],"ol",{},[3765,3930,3931,3934],{},[3747,3932,3933],{},"Зміни зберігаються локально"," (MMKV, SQLite, Realm) одразу — без чекання на сервер.",[3765,3936,3937,3940],{},[3747,3938,3939],{},"UI оновлюється миттєво"," — користувач бачить свою нову поїздку в списку через мілісекунди.",[3765,3942,3943,3946],{},[3747,3944,3945],{},"Фонова черга"," (outbox) автоматично відправляє зміни на сервер, коли з'являється мережа.",[3765,3948,3949,3952],{},[3747,3950,3951],{},"Статус синхронізації"," показує, чи дані вже на сервері, чи ще в черзі.",[3954,3955,3956,3959],"tip",{},[3747,3957,3958],{},"Аналогія:"," уявіть папку «Вихідні» в email-клієнті. Ви пишете листа без інтернету, натискаєте «Надіслати» — і лист одразу потрапляє в папку «Вихідні». Коли з'являється мережа, клієнт сам відправляє всі листи з черги. Офлайн-first працює так само: ваші зміни — це «листи», а outbox — черга на відправку.",[3836,3961],{},[3843,3963,3965],{"id":3964},"_12-outbox-pattern-черга-змін","1.2. Outbox Pattern — черга змін",[3743,3967,3968,3971],{},[3747,3969,3970],{},"Outbox"," (аутбокс, «вихідна черга») — це локальна таблиця або список операцій, які треба відправити на сервер. Кожна операція (створення поїздки, оновлення місця, видалення фото) зберігається як запис у черзі з полями:",[3973,3974,3979],"pre",{"className":3975,"code":3976,"language":3977,"meta":3978,"style":3978},"language-typescript shiki shiki-themes light-plus dark-plus dark-plus","type OutboxItem = {\n  id: string;              \u002F\u002F UUID локального запису\n  operation: 'CREATE' | 'UPDATE' | 'DELETE';\n  resource: 'trip' | 'place' | 'photo';\n  payload: unknown;        \u002F\u002F дані для відправки (JSON)\n  createdAt: number;       \u002F\u002F timestamp створення (для сортування)\n  retryCount: number;      \u002F\u002F скільки разів намагалися відправити\n  lastError?: string;      \u002F\u002F текст останньої помилки (якщо була)\n};\n","typescript","",[3780,3980,3981,3998,4018,4044,4067,4084,4101,4117,4133],{"__ignoreMap":3978},[3982,3983,3986,3990,3994],"span",{"class":3984,"line":3985},"line",1,[3982,3987,3989],{"class":3988},"su1O8","type",[3982,3991,3993],{"class":3992},"sN1BT"," OutboxItem",[3982,3995,3997],{"class":3996},"sHH4Y"," = {\n",[3982,3999,4001,4005,4008,4011,4014],{"class":3984,"line":4000},2,[3982,4002,4004],{"class":4003},"siwwj","  id",[3982,4006,4007],{"class":3996},": ",[3982,4009,4010],{"class":3992},"string",[3982,4012,4013],{"class":3996},";              ",[3982,4015,4017],{"class":4016},"spJ8K","\u002F\u002F UUID локального запису\n",[3982,4019,4021,4024,4026,4030,4033,4036,4038,4041],{"class":3984,"line":4020},3,[3982,4022,4023],{"class":4003},"  operation",[3982,4025,4007],{"class":3996},[3982,4027,4029],{"class":4028},"sbdoH","'CREATE'",[3982,4031,4032],{"class":3996}," | ",[3982,4034,4035],{"class":4028},"'UPDATE'",[3982,4037,4032],{"class":3996},[3982,4039,4040],{"class":4028},"'DELETE'",[3982,4042,4043],{"class":3996},";\n",[3982,4045,4047,4050,4052,4055,4057,4060,4062,4065],{"class":3984,"line":4046},4,[3982,4048,4049],{"class":4003},"  resource",[3982,4051,4007],{"class":3996},[3982,4053,4054],{"class":4028},"'trip'",[3982,4056,4032],{"class":3996},[3982,4058,4059],{"class":4028},"'place'",[3982,4061,4032],{"class":3996},[3982,4063,4064],{"class":4028},"'photo'",[3982,4066,4043],{"class":3996},[3982,4068,4070,4073,4075,4078,4081],{"class":3984,"line":4069},5,[3982,4071,4072],{"class":4003},"  payload",[3982,4074,4007],{"class":3996},[3982,4076,4077],{"class":3992},"unknown",[3982,4079,4080],{"class":3996},";        ",[3982,4082,4083],{"class":4016},"\u002F\u002F дані для відправки (JSON)\n",[3982,4085,4087,4090,4092,4095,4098],{"class":3984,"line":4086},6,[3982,4088,4089],{"class":4003},"  createdAt",[3982,4091,4007],{"class":3996},[3982,4093,4094],{"class":3992},"number",[3982,4096,4097],{"class":3996},";       ",[3982,4099,4100],{"class":4016},"\u002F\u002F timestamp створення (для сортування)\n",[3982,4102,4104,4107,4109,4111,4114],{"class":3984,"line":4103},7,[3982,4105,4106],{"class":4003},"  retryCount",[3982,4108,4007],{"class":3996},[3982,4110,4094],{"class":3992},[3982,4112,4113],{"class":3996},";      ",[3982,4115,4116],{"class":4016},"\u002F\u002F скільки разів намагалися відправити\n",[3982,4118,4120,4123,4126,4128,4130],{"class":3984,"line":4119},8,[3982,4121,4122],{"class":4003},"  lastError",[3982,4124,4125],{"class":3996},"?: ",[3982,4127,4010],{"class":3992},[3982,4129,4113],{"class":3996},[3982,4131,4132],{"class":4016},"\u002F\u002F текст останньої помилки (якщо була)\n",[3982,4134,4136],{"class":3984,"line":4135},9,[3982,4137,4138],{"class":3996},"};\n",[3743,4140,4141],{},[3747,4142,4143],{},"Як працює outbox:",[3927,4145,4146,4152,4161,4167,4170,4184],{},[3765,4147,4148,4149,3823],{},"Користувач створює поїздку → застосунок одразу записує її в локальну базу SQLite з ",[3780,4150,4151],{},"syncStatus: 'pending'",[3765,4153,4154,4155,4007,4158,3823],{},"Одночасно додається запис у таблицю ",[3780,4156,4157],{},"outbox",[3780,4159,4160],{},"{ operation: 'CREATE', resource: 'trip', payload: { title, startDate, ... } }",[3765,4162,4163,4166],{},[3747,4164,4165],{},"Фоновий процес"," (useEffect, setInterval, або нативний WorkManager\u002FBackgroundTasks) періодично перевіряє outbox.",[3765,4168,4169],{},"Якщо є мережа — бере перший запис з черги, робить POST\u002FPATCH\u002FDELETE на API.",[3765,4171,4172,4173,4175,4176,4179,4180,4183],{},"Якщо сервер відповідає ",[3780,4174,3856],{}," — видаляє запис з outbox, оновлює ",[3780,4177,4178],{},"syncStatus: 'synced'"," у локальній базі, записує ",[3780,4181,4182],{},"serverId"," (якщо сервер повернув ID).",[3765,4185,4186,4187,4190,4191,4194],{},"Якщо помилка (timeout, 500, 409 conflict) — збільшує ",[3780,4188,4189],{},"retryCount",", записує ",[3780,4192,4193],{},"lastError",", залишає запис у черзі для наступної спроби.",[3825,4196,4197,4199],{},[3747,4198,3970],{}," — це локальна черга операцій, які застосунок має відправити на сервер. Кожен запис у черзі описує одну зміну (створити, оновити, видалити) і зберігає payload для запиту.",[3743,4201,4202],{},[3747,4203,4204],{},"Переваги outbox:",[3762,4206,4207,4213,4223],{},[3765,4208,4209,4212],{},[3747,4210,4211],{},"Гарантія доставки:"," навіть якщо застосунок закриють або телефон вимкнеться, черга лишається в локальній базі — при наступному запуску синхронізація продовжиться.",[3765,4214,4215,4218,4219,4222],{},[3747,4216,4217],{},"Порядок операцій:"," outbox обробляє записи за часом створення (",[3780,4220,4221],{},"createdAt",") — спочатку старі, потім нові. Це важливо, якщо одна операція залежить від іншої (наприклад, спочатку створити поїздку, потім додати до неї місце).",[3765,4224,4225,4228],{},[3747,4226,4227],{},"Retry-логіка:"," якщо запит не вдався, запис лишається в черзі, і застосунок спробує знову через кілька секунд або хвилин (exponential backoff).",[3836,4230],{},[3843,4232,4234],{"id":4233},"_13-syncstatus-стани-синхронізації","1.3. syncStatus — стани синхронізації",[3743,4236,4237,4238,4242],{},"Кожен запис у локальній базі (поїздка, місце, фото) має поле ",[3747,4239,4240],{},[3780,4241,3818],{},", яке показує, чи дані вже на сервері:",[3973,4244,4246],{"className":3975,"code":4245,"language":3977,"meta":3978,"style":3978},"type SyncStatus = \n  | 'pending'   \u002F\u002F локально створено, але ще не відправлено\n  | 'syncing'   \u002F\u002F зараз відправляється на сервер\n  | 'synced'    \u002F\u002F успішно синхронізовано, є serverId\n  | 'error';    \u002F\u002F помилка синхронізації (conflict, server error)\n",[3780,4247,4248,4258,4269,4279,4289],{"__ignoreMap":3978},[3982,4249,4250,4252,4255],{"class":3984,"line":3985},[3982,4251,3989],{"class":3988},[3982,4253,4254],{"class":3992}," SyncStatus",[3982,4256,4257],{"class":3996}," = \n",[3982,4259,4260,4263,4266],{"class":3984,"line":4000},[3982,4261,4262],{"class":3996},"  | ",[3982,4264,4265],{"class":4028},"'pending'",[3982,4267,4268],{"class":4016},"   \u002F\u002F локально створено, але ще не відправлено\n",[3982,4270,4271,4273,4276],{"class":3984,"line":4020},[3982,4272,4262],{"class":3996},[3982,4274,4275],{"class":4028},"'syncing'",[3982,4277,4278],{"class":4016},"   \u002F\u002F зараз відправляється на сервер\n",[3982,4280,4281,4283,4286],{"class":3984,"line":4046},[3982,4282,4262],{"class":3996},[3982,4284,4285],{"class":4028},"'synced'",[3982,4287,4288],{"class":4016},"    \u002F\u002F успішно синхронізовано, є serverId\n",[3982,4290,4291,4293,4296,4299],{"class":3984,"line":4069},[3982,4292,4262],{"class":3996},[3982,4294,4295],{"class":4028},"'error'",[3982,4297,4298],{"class":3996},";    ",[3982,4300,4301],{"class":4016},"\u002F\u002F помилка синхронізації (conflict, server error)\n",[3743,4303,4304],{},[3747,4305,4306],{},"Життєвий цикл запису:",[3927,4308,4309,4320,4329,4349],{},[3765,4310,4311,4314,4315,3783,4317,3823],{},[3747,4312,4313],{},"Створення офлайн:"," користувач додає поїздку без мережі → ",[3780,4316,4151],{},[3780,4318,4319],{},"serverId: null",[3765,4321,4322,4325,4326,3823],{},[3747,4323,4324],{},"Початок синхронізації:"," outbox-worker бере запис з черги → ",[3780,4327,4328],{},"syncStatus: 'syncing'",[3765,4330,4331,4334,4335,4338,4339,4342,4343,3783,4345,4348],{},[3747,4332,4333],{},"Успіх:"," сервер повертає ",[3780,4336,4337],{},"201 Created"," з ",[3780,4340,4341],{},"{ id: \"srv-123\" }"," → ",[3780,4344,4178],{},[3780,4346,4347],{},"serverId: \"srv-123\"",", запис видаляється з outbox.",[3765,4350,4351,4334,4354,4357,4358,3783,4361,4364],{},[3747,4352,4353],{},"Помилка:",[3780,4355,4356],{},"409 Conflict"," або timeout → ",[3780,4359,4360],{},"syncStatus: 'error'",[3780,4362,4363],{},"syncError: \"Conflict: trip with this title exists\"",", запис лишається в outbox для retry.",[3743,4366,4367],{},[3747,4368,4369],{},"У UI це виглядає так:",[3862,4371,4372,4381],{},[3865,4373,4374],{},[3868,4375,4376,4378],{},[3871,4377,3818],{},[3871,4379,4380],{},"Що бачить користувач",[3878,4382,4383,4392,4402,4411],{},[3868,4384,4385,4389],{},[3883,4386,4387],{},[3780,4388,3782],{},[3883,4390,4391],{},"Іконка «хмаринка з годинником» або сірий badge «Не синхронізовано»",[3868,4393,4394,4399],{},[3883,4395,4396],{},[3780,4397,4398],{},"syncing",[3883,4400,4401],{},"Спінер або анімація «відправляється»",[3868,4403,4404,4408],{},[3883,4405,4406],{},[3780,4407,3786],{},[3883,4409,4410],{},"Зелена галочка або просто немає badge (нормальний стан)",[3868,4412,4413,4417],{},[3883,4414,4415],{},[3780,4416,3789],{},[3883,4418,4419],{},"Червона іконка + кнопка «Повторити» + текст помилки в деталях",[4421,4422,4423,4426,4427,4429,4430,4433,4434,4436,4437,4440,4441,4444,4445,4448],"warning",{},[3747,4424,4425],{},"Типова плутанина:"," не плутайте ",[3780,4428,3818],{}," (чи дані на сервері) з ",[3780,4431,4432],{},"loadingStatus"," RTK Query (чи запит іде зараз). ",[3780,4435,3818],{}," — це ",[3747,4438,4439],{},"властивість даних"," у локальній базі, а ",[3780,4442,4443],{},"isLoading"," RTK Query — це ",[3747,4446,4447],{},"стан UI"," під час fetch. Офлайн-first працює навпаки: спочатку дані в базі, потім запит у фоні.",[3836,4450],{},[3843,4452,4454],{"id":4453},"_14-конфлікти-conflicts-і-стратегії-розвязання","1.4. Конфлікти (conflicts) і стратегії розв'язання",[3743,4456,4457,4460],{},[3747,4458,4459],{},"Конфлікт"," виникає, коли:",[3927,4462,4463,4472,4478],{},[3765,4464,4465,4466,3783,4469,4471],{},"Користувач змінює поїздку офлайн (локально ",[3780,4467,4468],{},"version: 3",[3780,4470,4151],{},").",[3765,4473,4474,4475,3823],{},"Інший користувач (або той самий на іншому пристрої) змінює ту саму поїздку онлайн — сервер має ",[3780,4476,4477],{},"version: 4",[3765,4479,4480,4481,4483,4484,4487],{},"Коли перший користувач синхронізується, сервер повертає ",[3780,4482,4356],{}," або ",[3780,4485,4486],{},"412 Precondition Failed"," — «ваша версія застаріла».",[3743,4489,4490],{},[3747,4491,4492],{},"Три стратегії розв'язання конфліктів:",[3862,4494,4495,4508],{},[3865,4496,4497],{},[3868,4498,4499,4502,4505],{},[3871,4500,4501],{},"Стратегія",[3871,4503,4504],{},"Що робить застосунок",[3871,4506,4507],{},"Коли доречно",[3878,4509,4510,4527,4540],{},[3868,4511,4512,4517,4524],{},[3883,4513,4514],{},[3747,4515,4516],{},"Last Write Wins (LWW)",[3883,4518,4519,4520,4523],{},"Приймає останню зміну за часом (",[3780,4521,4522],{},"updatedAt","); сервер затирає старішу версію.",[3883,4525,4526],{},"Прості дані (налаштування, профіль), де конфлікти рідкі і не критичні.",[3868,4528,4529,4534,4537],{},[3883,4530,4531],{},[3747,4532,4533],{},"Server Wins",[3883,4535,4536],{},"Завжди приймає серверну версію; локальні зміни скидаються.",[3883,4538,4539],{},"Критичні дані (баланс, inventory), де сервер — єдине джерело істини.",[3868,4541,4542,4547,4550],{},[3883,4543,4544],{},[3747,4545,4546],{},"Manual Merge",[3883,4548,4549],{},"Показує користувачу обидві версії (локальну і серверну), просить вибрати або об'єднати вручну.",[3883,4551,4552],{},"Текстові документи, складні об'єкти (CRM-запис з 20 полями), де втрата даних неприпустима.",[3743,4554,4555,4558,4559,4562,4563,4566,4567,4569,4570,3823],{},[3747,4556,4557],{},"У Nomad"," ми використовуємо ",[3747,4560,4561],{},"Last Write Wins"," для простоти: якщо сервер повертає ",[3780,4564,4565],{},"409",", застосунок порівнює ",[3780,4568,4522],{}," локального і серверного запису — новіший виграє. Якщо серверний новіший — застосунок замінює локальні дані, outbox-запис видаляється. Якщо локальний новіший — надсилаємо force-update з ",[3780,4571,4572],{},"?force=true",[3825,4574,4575,4578,4579,4581],{},[3747,4576,4577],{},"Конфлікт синхронізації"," — це ситуація, коли локальна і серверна версії запису різняться, і треба вирішити, яку залишити. Найпростіша стратегія — ",[3747,4580,4561],{},": порівняти timestamp і взяти новішу версію.",[3743,4583,4584],{},[3747,4585,4586],{},"Приклад конфлікту в Nomad:",[3927,4588,4589,4601,4611,4617],{},[3765,4590,4591,4592,4342,4595,3783,4598,3823],{},"Користувач офлайн редагує поїздку ",[3780,4593,4594],{},"\"Київ\"",[3780,4596,4597],{},"\"Київ + Львів\"",[3780,4599,4600],{},"updatedAt: 2026-08-11T10:00:00Z",[3765,4602,4603,4604,3783,4607,4610],{},"Інший пристрій онлайн редагує ту саму поїздку → ",[3780,4605,4606],{},"\"Київ + Одеса\"",[3780,4608,4609],{},"updatedAt: 2026-08-11T10:05:00Z"," (на 5 хвилин пізніше).",[3765,4612,4613,4614,4616],{},"Перший пристрій синхронізується, сервер повертає ",[3780,4615,4565],{}," + серверну версію.",[3765,4618,4619,4620,4623,4624,4627],{},"Застосунок порівнює: серверна ",[3780,4621,4622],{},"10:05"," > локальна ",[3780,4625,4626],{},"10:00"," → приймає серверну, локальна зміна губиться (або показуємо toast «Серверна версія новіша, ваші зміни скинуто»).",[3743,4629,4630,4631,4483,4634,4637],{},"У production-застосунках часто додають ",[3747,4632,4633],{},"operational transformation",[3747,4635,4636],{},"CRDT"," (conflict-free replicated data types) для автоматичного злиття змін без втрати даних — але це складна тема, яку ми тут не розглядаємо. Для навчального проєкту достатньо LWW.",[3836,4639],{},[3843,4641,4643],{"id":4642},"_15-offline-ux-як-показати-користувачу-що-він-офлайн","1.5. Offline UX — як показати користувачу, що він офлайн",[3743,4645,4646,4647,4650],{},"Користувач має ",[3747,4648,4649],{},"завжди розуміти",", чи застосунок зараз онлайн чи офлайн, і чи його зміни синхронізовано. Погано, коли застосунок «мовчить» — людина думає, що все OK, а насправді дані не на сервері і можуть загубитися при видаленні застосунку.",[3743,4652,4653],{},[3747,4654,4655],{},"Елементи offline UX:",[3862,4657,4658,4671],{},[3865,4659,4660],{},[3868,4661,4662,4665,4668],{},[3871,4663,4664],{},"Елемент",[3871,4666,4667],{},"Що показує",[3871,4669,4670],{},"Де розміщувати",[3878,4672,4673,4686,4705,4720,4733],{},[3868,4674,4675,4680,4683],{},[3883,4676,4677],{},[3747,4678,4679],{},"Network banner",[3883,4681,4682],{},"«Офлайн-режим» (жовтий) \u002F «Онлайн» (зелений, зникає через 2 с)",[3883,4684,4685],{},"Верх екрана (sticky), над навігацією",[3868,4687,4688,4693,4702],{},[3883,4689,4690],{},[3747,4691,4692],{},"Sync badge на картці",[3883,4694,4695,4697,4698,4697,4700],{},[3780,4696,3782],{}," \u002F ",[3780,4699,4398],{},[3780,4701,3789],{},[3883,4703,4704],{},"Куточок картки поїздки\u002Fмісця",[3868,4706,4707,4712,4715],{},[3883,4708,4709],{},[3747,4710,4711],{},"Retry button",[3883,4713,4714],{},"«Повторити синхронізацію»",[3883,4716,4717,4718],{},"Деталі запису з ",[3780,4719,4360],{},[3868,4721,4722,4727,4730],{},[3883,4723,4724],{},[3747,4725,4726],{},"Sync indicator у header",[3883,4728,4729],{},"Іконка «хмаринка» з лічильником pending-записів",[3883,4731,4732],{},"Права частина заголовка списку",[3868,4734,4735,4740,4743],{},[3883,4736,4737],{},[3747,4738,4739],{},"Toast при переході online",[3883,4741,4742],{},"«З'єднання відновлено, синхронізуємо…»",[3883,4744,4745],{},"Центр екрана, 2–3 с",[3743,4747,4748],{},[3747,4749,4750],{},"Правила offline UX:",[3927,4752,4753,4759,4765,4771,4777],{},[3765,4754,4755,4758],{},[3747,4756,4757],{},"Не блокувати UI:"," користувач може продовжувати працювати офлайн, навіть якщо частина даних не синхронізована.",[3765,4760,4761,4764],{},[3747,4762,4763],{},"Показувати прогрес:"," якщо в outbox 10 записів, показати «Синхронізація 3\u002F10» або прогрес-бар.",[3765,4766,4767,4770],{},[3747,4768,4769],{},"Чітка помилка:"," якщо sync fail — не просто «Помилка», а «Сервер недоступний» або «Конфлікт: ця поїздка вже існує».",[3765,4772,4773,4776],{},[3747,4774,4775],{},"Retry без зусиль:"," кнопка «Повторити» або автоматичний retry через 30 с \u002F 1 хв \u002F 5 хв (exponential backoff).",[3765,4778,4779,4782],{},[3747,4780,4781],{},"Оптимістичні оновлення:"," показуємо зміни одразу (optimistic UI), а якщо сервер відхилить — відкочуємо з toast «Зміну не збережено».",[3954,4784,4785,4788,4789,4792],{},[3747,4786,4787],{},"Оптимістичне оновлення (optimistic UI)"," — це коли застосунок показує зміну в інтерфейсі одразу, ",[3747,4790,4791],{},"до відповіді сервера",". Якщо запит успішний — нічого не змінюється. Якщо помилка — UI повертається до попереднього стану з повідомленням про помилку. Це робить застосунок швидшим на відчуття.",[3836,4794],{},[3843,4796,4798],{"id":4797},"_16-архітектура-offline-first-у-react-native-з-rtk","1.6. Архітектура offline-first у React Native з RTK",[3743,4800,4801],{},"Тепер з'єднаємо всі частини в одну систему. У застосунку на RTK + RTK Query + SQLite архітектура виглядає так:",[4803,4804,4805],"plant-uml",{},[3973,4806,4810],{"className":4807,"code":4808,"language":4809,"meta":3978,"style":3978},"language-plantuml shiki shiki-themes light-plus dark-plus dark-plus","@startuml\nskinparam backgroundColor #ffffff\nskinparam componentStyle rectangle\n\npackage \"React Components\" {\n  [TripsList]\n  [TripForm]\n}\n\npackage \"RTK Store\" {\n  [tripsSlice]\n  [outboxSlice]\n  [tripsApi (RTK Query)]\n}\n\npackage \"Local DB (SQLite)\" {\n  database \"trips table\" as TripsDB\n  database \"outbox table\" as OutboxDB\n}\n\npackage \"Sync Engine\" {\n  [useSyncWorker hook]\n}\n\ncloud \"Backend API\" as API\n\n[TripForm] --> [tripsSlice] : dispatch createTrip\n[tripsSlice] --> TripsDB : write trip (syncStatus: pending)\n[tripsSlice] --> OutboxDB : add outbox item (CREATE)\n[TripsList] \u003C-- TripsDB : read trips\n\n[useSyncWorker hook] --> OutboxDB : poll every 10s\n[useSyncWorker hook] --> API : POST \u002Ftrips\nAPI --> [useSyncWorker hook] : 201 + serverId\n[useSyncWorker hook] --> TripsDB : update syncStatus: synced\n[useSyncWorker hook] --> OutboxDB : delete outbox item\n\n[tripsApi (RTK Query)] --> API : fetch trips (online)\n[tripsApi (RTK Query)] --> TripsDB : cache\n\n@enduml\n","plantuml",[3780,4811,4812,4817,4822,4827,4833,4838,4843,4848,4853,4857,4863,4869,4875,4881,4886,4891,4897,4903,4909,4914,4919,4925,4931,4936,4941,4947,4952,4958,4964,4970,4976,4981,4987,4993,4999,5005,5011,5016,5022,5028,5033],{"__ignoreMap":3978},[3982,4813,4814],{"class":3984,"line":3985},[3982,4815,4816],{},"@startuml\n",[3982,4818,4819],{"class":3984,"line":4000},[3982,4820,4821],{},"skinparam backgroundColor #ffffff\n",[3982,4823,4824],{"class":3984,"line":4020},[3982,4825,4826],{},"skinparam componentStyle rectangle\n",[3982,4828,4829],{"class":3984,"line":4046},[3982,4830,4832],{"emptyLinePlaceholder":4831},true,"\n",[3982,4834,4835],{"class":3984,"line":4069},[3982,4836,4837],{},"package \"React Components\" {\n",[3982,4839,4840],{"class":3984,"line":4086},[3982,4841,4842],{},"  [TripsList]\n",[3982,4844,4845],{"class":3984,"line":4103},[3982,4846,4847],{},"  [TripForm]\n",[3982,4849,4850],{"class":3984,"line":4119},[3982,4851,4852],{},"}\n",[3982,4854,4855],{"class":3984,"line":4135},[3982,4856,4832],{"emptyLinePlaceholder":4831},[3982,4858,4860],{"class":3984,"line":4859},10,[3982,4861,4862],{},"package \"RTK Store\" {\n",[3982,4864,4866],{"class":3984,"line":4865},11,[3982,4867,4868],{},"  [tripsSlice]\n",[3982,4870,4872],{"class":3984,"line":4871},12,[3982,4873,4874],{},"  [outboxSlice]\n",[3982,4876,4878],{"class":3984,"line":4877},13,[3982,4879,4880],{},"  [tripsApi (RTK Query)]\n",[3982,4882,4884],{"class":3984,"line":4883},14,[3982,4885,4852],{},[3982,4887,4889],{"class":3984,"line":4888},15,[3982,4890,4832],{"emptyLinePlaceholder":4831},[3982,4892,4894],{"class":3984,"line":4893},16,[3982,4895,4896],{},"package \"Local DB (SQLite)\" {\n",[3982,4898,4900],{"class":3984,"line":4899},17,[3982,4901,4902],{},"  database \"trips table\" as TripsDB\n",[3982,4904,4906],{"class":3984,"line":4905},18,[3982,4907,4908],{},"  database \"outbox table\" as OutboxDB\n",[3982,4910,4912],{"class":3984,"line":4911},19,[3982,4913,4852],{},[3982,4915,4917],{"class":3984,"line":4916},20,[3982,4918,4832],{"emptyLinePlaceholder":4831},[3982,4920,4922],{"class":3984,"line":4921},21,[3982,4923,4924],{},"package \"Sync Engine\" {\n",[3982,4926,4928],{"class":3984,"line":4927},22,[3982,4929,4930],{},"  [useSyncWorker hook]\n",[3982,4932,4934],{"class":3984,"line":4933},23,[3982,4935,4852],{},[3982,4937,4939],{"class":3984,"line":4938},24,[3982,4940,4832],{"emptyLinePlaceholder":4831},[3982,4942,4944],{"class":3984,"line":4943},25,[3982,4945,4946],{},"cloud \"Backend API\" as API\n",[3982,4948,4950],{"class":3984,"line":4949},26,[3982,4951,4832],{"emptyLinePlaceholder":4831},[3982,4953,4955],{"class":3984,"line":4954},27,[3982,4956,4957],{},"[TripForm] --> [tripsSlice] : dispatch createTrip\n",[3982,4959,4961],{"class":3984,"line":4960},28,[3982,4962,4963],{},"[tripsSlice] --> TripsDB : write trip (syncStatus: pending)\n",[3982,4965,4967],{"class":3984,"line":4966},29,[3982,4968,4969],{},"[tripsSlice] --> OutboxDB : add outbox item (CREATE)\n",[3982,4971,4973],{"class":3984,"line":4972},30,[3982,4974,4975],{},"[TripsList] \u003C-- TripsDB : read trips\n",[3982,4977,4979],{"class":3984,"line":4978},31,[3982,4980,4832],{"emptyLinePlaceholder":4831},[3982,4982,4984],{"class":3984,"line":4983},32,[3982,4985,4986],{},"[useSyncWorker hook] --> OutboxDB : poll every 10s\n",[3982,4988,4990],{"class":3984,"line":4989},33,[3982,4991,4992],{},"[useSyncWorker hook] --> API : POST \u002Ftrips\n",[3982,4994,4996],{"class":3984,"line":4995},34,[3982,4997,4998],{},"API --> [useSyncWorker hook] : 201 + serverId\n",[3982,5000,5002],{"class":3984,"line":5001},35,[3982,5003,5004],{},"[useSyncWorker hook] --> TripsDB : update syncStatus: synced\n",[3982,5006,5008],{"class":3984,"line":5007},36,[3982,5009,5010],{},"[useSyncWorker hook] --> OutboxDB : delete outbox item\n",[3982,5012,5014],{"class":3984,"line":5013},37,[3982,5015,4832],{"emptyLinePlaceholder":4831},[3982,5017,5019],{"class":3984,"line":5018},38,[3982,5020,5021],{},"[tripsApi (RTK Query)] --> API : fetch trips (online)\n",[3982,5023,5025],{"class":3984,"line":5024},39,[3982,5026,5027],{},"[tripsApi (RTK Query)] --> TripsDB : cache\n",[3982,5029,5031],{"class":3984,"line":5030},40,[3982,5032,4832],{"emptyLinePlaceholder":4831},[3982,5034,5036],{"class":3984,"line":5035},41,[3982,5037,5038],{},"@enduml\n",[3743,5040,5041],{},[3747,5042,5043],{},"Потік даних:",[3927,5045,5046,5079,5134],{},[3765,5047,5048,5051],{},[3747,5049,5050],{},"Створення запису (офлайн):",[3762,5052,5053,5059,5067,5076],{},[3765,5054,5055,5056,3823],{},"Користувач натискає «Створити поїздку» → ",[3780,5057,5058],{},"dispatch(createTrip({ title, startDate }))",[3765,5060,5061,5064,5065,3823],{},[3780,5062,5063],{},"tripsSlice"," генерує локальний UUID, записує поїздку в SQLite з ",[3780,5066,4151],{},[3765,5068,5069,5070,5072,5073,3823],{},"Одночасно додає запис у ",[3780,5071,4157],{}," таблицю: ",[3780,5074,5075],{},"{ operation: 'CREATE', resource: 'trip', payload: { title, startDate } }",[3765,5077,5078],{},"UI одразу показує нову поїздку в списку з badge «Не синхронізовано».",[3765,5080,5081,5084],{},[3747,5082,5083],{},"Синхронізація (фон):",[3762,5085,5086,5097,5103,5109,5122],{},[3765,5087,5088,5089,5092,5093,5096],{},"Хук ",[3780,5090,5091],{},"useSyncWorker"," запускається кожні 10 секунд (або на подію ",[3780,5094,5095],{},"online"," від NetInfo).",[3765,5098,5099,5100,3823],{},"Перевіряє outbox: ",[3780,5101,5102],{},"SELECT * FROM outbox ORDER BY createdAt LIMIT 1",[3765,5104,5105,5106,3823],{},"Якщо є запис — робить ",[3780,5107,5108],{},"fetch('POST \u002Fapi\u002Ftrips', { body: payload })",[3765,5110,5111,5112,5115,5116,3783,5118,5121],{},"Якщо ",[3780,5113,5114],{},"201 OK"," → оновлює trip у SQLite: ",[3780,5117,4178],{},[3780,5119,5120],{},"serverId: response.id",", видаляє запис з outbox.",[3765,5123,5124,5125,3783,5127,5130,5131,5133],{},"Якщо помилка → ",[3780,5126,4360],{},[3780,5128,5129],{},"syncError: response.message",", збільшує ",[3780,5132,4189],{},", залишає в outbox.",[3765,5135,5136,5139],{},[3747,5137,5138],{},"Завантаження з сервера (онлайн):",[3762,5140,5141,5148,5158],{},[3765,5142,5143,5144,5147],{},"При запуску застосунку (або pull-to-refresh) ",[3780,5145,5146],{},"tripsApi.useGetTripsQuery()"," завантажує список із сервера.",[3765,5149,5150,5151,5154,5155,5157],{},"RTK Query кешує результат, але ",[3747,5152,5153],{},"не затирає"," локальні ",[3780,5156,3782],{},"-записи — вони існують лише локально, поки не синхронізуються.",[3765,5159,5160,5161,5163,5164,5167,5168,5170],{},"Merge-логіка: якщо є запис з ",[3780,5162,4182],{}," у локальній базі і той самий ",[3780,5165,5166],{},"id"," на сервері — оновлюємо локальну версію серверною (якщо ",[3780,5169,4522],{}," серверної новіше).",[3825,5172,5173,5176,5177,5180],{},[3747,5174,5175],{},"Offline-first у RTK"," — це поєднання локальної бази (джерело істини для UI), outbox-черги (операції на відправку) і фонового sync-worker (обробка черги). RTK Query використовується для завантаження даних з сервера, але ",[3747,5178,5179],{},"не замінює"," локальну базу — вона лише доповнює її.",[3836,5182],{},[3843,5184,5186],{"id":5185},"_17-netinfo-визначення-стану-мережі","1.7. NetInfo — визначення стану мережі",[3743,5188,5189,5190,5195],{},"Щоб розуміти, коли запускати синхронізацію, застосунок має знати, чи є інтернет. У React Native для цього використовують бібліотеку ",[3747,5191,5192],{},[3780,5193,5194],{},"@react-native-community\u002Fnetinfo"," (NetInfo).",[3743,5197,5198],{},[3747,5199,5200],{},"Що вміє NetInfo:",[3973,5202,5204],{"className":3975,"code":5203,"language":3977,"meta":3978,"style":3978},"import NetInfo from '@react-native-community\u002Fnetinfo';\n\n\u002F\u002F Одноразова перевірка\nconst state = await NetInfo.fetch();\nconsole.log(state.isConnected);  \u002F\u002F true | false\nconsole.log(state.type);         \u002F\u002F 'wifi' | 'cellular' | 'none' | ...\n\n\u002F\u002F Підписка на зміни\nconst unsubscribe = NetInfo.addEventListener(state => {\n  if (state.isConnected) {\n    console.log('Online, starting sync...');\n    syncWorker.run();\n  } else {\n    console.log('Offline, pausing sync');\n  }\n});\n",[3780,5205,5206,5223,5227,5232,5258,5285,5307,5311,5316,5343,5359,5376,5388,5398,5413,5418],{"__ignoreMap":3978},[3982,5207,5208,5212,5215,5218,5221],{"class":3984,"line":3985},[3982,5209,5211],{"class":5210},"s8xlr","import",[3982,5213,5214],{"class":4003}," NetInfo",[3982,5216,5217],{"class":5210}," from",[3982,5219,5220],{"class":4028}," '@react-native-community\u002Fnetinfo'",[3982,5222,4043],{"class":3996},[3982,5224,5225],{"class":3984,"line":4000},[3982,5226,4832],{"emptyLinePlaceholder":4831},[3982,5228,5229],{"class":3984,"line":4020},[3982,5230,5231],{"class":4016},"\u002F\u002F Одноразова перевірка\n",[3982,5233,5234,5237,5241,5244,5247,5249,5251,5255],{"class":3984,"line":4046},[3982,5235,5236],{"class":3988},"const",[3982,5238,5240],{"class":5239},"s-QsJ"," state",[3982,5242,5243],{"class":3996}," = ",[3982,5245,5246],{"class":5210},"await",[3982,5248,5214],{"class":4003},[3982,5250,3823],{"class":3996},[3982,5252,5254],{"class":5253},"s8Opu","fetch",[3982,5256,5257],{"class":3996},"();\n",[3982,5259,5260,5263,5265,5268,5271,5274,5276,5279,5282],{"class":3984,"line":4069},[3982,5261,5262],{"class":4003},"console",[3982,5264,3823],{"class":3996},[3982,5266,5267],{"class":5253},"log",[3982,5269,5270],{"class":3996},"(",[3982,5272,5273],{"class":4003},"state",[3982,5275,3823],{"class":3996},[3982,5277,5278],{"class":4003},"isConnected",[3982,5280,5281],{"class":3996},");  ",[3982,5283,5284],{"class":4016},"\u002F\u002F true | false\n",[3982,5286,5287,5289,5291,5293,5295,5297,5299,5301,5304],{"class":3984,"line":4086},[3982,5288,5262],{"class":4003},[3982,5290,3823],{"class":3996},[3982,5292,5267],{"class":5253},[3982,5294,5270],{"class":3996},[3982,5296,5273],{"class":4003},[3982,5298,3823],{"class":3996},[3982,5300,3989],{"class":4003},[3982,5302,5303],{"class":3996},");         ",[3982,5305,5306],{"class":4016},"\u002F\u002F 'wifi' | 'cellular' | 'none' | ...\n",[3982,5308,5309],{"class":3984,"line":4103},[3982,5310,4832],{"emptyLinePlaceholder":4831},[3982,5312,5313],{"class":3984,"line":4119},[3982,5314,5315],{"class":4016},"\u002F\u002F Підписка на зміни\n",[3982,5317,5318,5320,5323,5325,5328,5330,5333,5335,5337,5340],{"class":3984,"line":4135},[3982,5319,5236],{"class":3988},[3982,5321,5322],{"class":5239}," unsubscribe",[3982,5324,5243],{"class":3996},[3982,5326,5327],{"class":4003},"NetInfo",[3982,5329,3823],{"class":3996},[3982,5331,5332],{"class":5253},"addEventListener",[3982,5334,5270],{"class":3996},[3982,5336,5273],{"class":4003},[3982,5338,5339],{"class":3988}," =>",[3982,5341,5342],{"class":3996}," {\n",[3982,5344,5345,5348,5350,5352,5354,5356],{"class":3984,"line":4859},[3982,5346,5347],{"class":5210},"  if",[3982,5349,3778],{"class":3996},[3982,5351,5273],{"class":4003},[3982,5353,3823],{"class":3996},[3982,5355,5278],{"class":4003},[3982,5357,5358],{"class":3996},") {\n",[3982,5360,5361,5364,5366,5368,5370,5373],{"class":3984,"line":4865},[3982,5362,5363],{"class":4003},"    console",[3982,5365,3823],{"class":3996},[3982,5367,5267],{"class":5253},[3982,5369,5270],{"class":3996},[3982,5371,5372],{"class":4028},"'Online, starting sync...'",[3982,5374,5375],{"class":3996},");\n",[3982,5377,5378,5381,5383,5386],{"class":3984,"line":4871},[3982,5379,5380],{"class":4003},"    syncWorker",[3982,5382,3823],{"class":3996},[3982,5384,5385],{"class":5253},"run",[3982,5387,5257],{"class":3996},[3982,5389,5390,5393,5396],{"class":3984,"line":4877},[3982,5391,5392],{"class":3996},"  } ",[3982,5394,5395],{"class":5210},"else",[3982,5397,5342],{"class":3996},[3982,5399,5400,5402,5404,5406,5408,5411],{"class":3984,"line":4883},[3982,5401,5363],{"class":4003},[3982,5403,3823],{"class":3996},[3982,5405,5267],{"class":5253},[3982,5407,5270],{"class":3996},[3982,5409,5410],{"class":4028},"'Offline, pausing sync'",[3982,5412,5375],{"class":3996},[3982,5414,5415],{"class":3984,"line":4888},[3982,5416,5417],{"class":3996},"  }\n",[3982,5419,5420],{"class":3984,"line":4893},[3982,5421,5422],{"class":3996},"});\n",[3743,5424,5425],{},[3747,5426,5427],{},"У застосунку це виглядає так:",[3973,5429,5431],{"className":3975,"code":5430,"language":3977,"meta":3978,"style":3978},"\u002F\u002F hooks\u002FuseNetworkStatus.ts\nimport { useEffect, useState } from 'react';\nimport NetInfo from '@react-native-community\u002Fnetinfo';\n\nexport function useNetworkStatus() {\n  const [isOnline, setIsOnline] = useState(true);\n\n  useEffect(() => {\n    \u002F\u002F Початкова перевірка\n    NetInfo.fetch().then(state => setIsOnline(state.isConnected ?? false));\n\n    \u002F\u002F Підписка на зміни\n    const unsubscribe = NetInfo.addEventListener(state => {\n      setIsOnline(state.isConnected ?? false);\n    });\n\n    return unsubscribe;\n  }, []);\n\n  return isOnline;\n}\n",[3780,5432,5433,5438,5464,5476,5480,5494,5522,5526,5539,5544,5585,5589,5594,5617,5636,5641,5645,5654,5659,5663,5673],{"__ignoreMap":3978},[3982,5434,5435],{"class":3984,"line":3985},[3982,5436,5437],{"class":4016},"\u002F\u002F hooks\u002FuseNetworkStatus.ts\n",[3982,5439,5440,5442,5445,5448,5450,5453,5456,5459,5462],{"class":3984,"line":4000},[3982,5441,5211],{"class":5210},[3982,5443,5444],{"class":3996}," { ",[3982,5446,5447],{"class":4003},"useEffect",[3982,5449,3783],{"class":3996},[3982,5451,5452],{"class":4003},"useState",[3982,5454,5455],{"class":3996}," } ",[3982,5457,5458],{"class":5210},"from",[3982,5460,5461],{"class":4028}," 'react'",[3982,5463,4043],{"class":3996},[3982,5465,5466,5468,5470,5472,5474],{"class":3984,"line":4020},[3982,5467,5211],{"class":5210},[3982,5469,5214],{"class":4003},[3982,5471,5217],{"class":5210},[3982,5473,5220],{"class":4028},[3982,5475,4043],{"class":3996},[3982,5477,5478],{"class":3984,"line":4046},[3982,5479,4832],{"emptyLinePlaceholder":4831},[3982,5481,5482,5485,5488,5491],{"class":3984,"line":4069},[3982,5483,5484],{"class":5210},"export",[3982,5486,5487],{"class":3988}," function",[3982,5489,5490],{"class":5253}," useNetworkStatus",[3982,5492,5493],{"class":3996},"() {\n",[3982,5495,5496,5499,5502,5505,5507,5510,5513,5515,5517,5520],{"class":3984,"line":4086},[3982,5497,5498],{"class":3988},"  const",[3982,5500,5501],{"class":3996}," [",[3982,5503,5504],{"class":5239},"isOnline",[3982,5506,3783],{"class":3996},[3982,5508,5509],{"class":5239},"setIsOnline",[3982,5511,5512],{"class":3996},"] = ",[3982,5514,5452],{"class":5253},[3982,5516,5270],{"class":3996},[3982,5518,5519],{"class":3988},"true",[3982,5521,5375],{"class":3996},[3982,5523,5524],{"class":3984,"line":4103},[3982,5525,4832],{"emptyLinePlaceholder":4831},[3982,5527,5528,5531,5534,5537],{"class":3984,"line":4119},[3982,5529,5530],{"class":5253},"  useEffect",[3982,5532,5533],{"class":3996},"(() ",[3982,5535,5536],{"class":3988},"=>",[3982,5538,5342],{"class":3996},[3982,5540,5541],{"class":3984,"line":4135},[3982,5542,5543],{"class":4016},"    \u002F\u002F Початкова перевірка\n",[3982,5545,5546,5549,5551,5553,5556,5559,5561,5563,5565,5568,5570,5572,5574,5576,5579,5582],{"class":3984,"line":4859},[3982,5547,5548],{"class":4003},"    NetInfo",[3982,5550,3823],{"class":3996},[3982,5552,5254],{"class":5253},[3982,5554,5555],{"class":3996},"().",[3982,5557,5558],{"class":5253},"then",[3982,5560,5270],{"class":3996},[3982,5562,5273],{"class":4003},[3982,5564,5339],{"class":3988},[3982,5566,5567],{"class":5253}," setIsOnline",[3982,5569,5270],{"class":3996},[3982,5571,5273],{"class":4003},[3982,5573,3823],{"class":3996},[3982,5575,5278],{"class":4003},[3982,5577,5578],{"class":3996}," ?? ",[3982,5580,5581],{"class":3988},"false",[3982,5583,5584],{"class":3996},"));\n",[3982,5586,5587],{"class":3984,"line":4865},[3982,5588,4832],{"emptyLinePlaceholder":4831},[3982,5590,5591],{"class":3984,"line":4871},[3982,5592,5593],{"class":4016},"    \u002F\u002F Підписка на зміни\n",[3982,5595,5596,5599,5601,5603,5605,5607,5609,5611,5613,5615],{"class":3984,"line":4877},[3982,5597,5598],{"class":3988},"    const",[3982,5600,5322],{"class":5239},[3982,5602,5243],{"class":3996},[3982,5604,5327],{"class":4003},[3982,5606,3823],{"class":3996},[3982,5608,5332],{"class":5253},[3982,5610,5270],{"class":3996},[3982,5612,5273],{"class":4003},[3982,5614,5339],{"class":3988},[3982,5616,5342],{"class":3996},[3982,5618,5619,5622,5624,5626,5628,5630,5632,5634],{"class":3984,"line":4883},[3982,5620,5621],{"class":5253},"      setIsOnline",[3982,5623,5270],{"class":3996},[3982,5625,5273],{"class":4003},[3982,5627,3823],{"class":3996},[3982,5629,5278],{"class":4003},[3982,5631,5578],{"class":3996},[3982,5633,5581],{"class":3988},[3982,5635,5375],{"class":3996},[3982,5637,5638],{"class":3984,"line":4888},[3982,5639,5640],{"class":3996},"    });\n",[3982,5642,5643],{"class":3984,"line":4893},[3982,5644,4832],{"emptyLinePlaceholder":4831},[3982,5646,5647,5650,5652],{"class":3984,"line":4899},[3982,5648,5649],{"class":5210},"    return",[3982,5651,5322],{"class":4003},[3982,5653,4043],{"class":3996},[3982,5655,5656],{"class":3984,"line":4905},[3982,5657,5658],{"class":3996},"  }, []);\n",[3982,5660,5661],{"class":3984,"line":4911},[3982,5662,4832],{"emptyLinePlaceholder":4831},[3982,5664,5665,5668,5671],{"class":3984,"line":4916},[3982,5666,5667],{"class":5210},"  return",[3982,5669,5670],{"class":4003}," isOnline",[3982,5672,4043],{"class":3996},[3982,5674,5675],{"class":3984,"line":4921},[3982,5676,4852],{"class":3996},[3743,5678,5679],{},[3747,5680,5681],{},"Використання в компонентах:",[3973,5683,5685],{"className":3975,"code":5684,"language":3977,"meta":3978,"style":3978},"function TripsList() {\n  const isOnline = useNetworkStatus();\n\n  return (\n    \u003CView>\n      {!isOnline && (\n        \u003CBanner variant=\"warning\">\n          Офлайн-режим. Зміни синхронізуються автоматично при появі мережі.\n        \u003C\u002FBanner>\n      )}\n      {\u002F* список поїздок *\u002F}\n    \u003C\u002FView>\n  );\n}\n",[3780,5686,5687,5697,5710,5714,5721,5732,5742,5761,5796,5805,5810,5820,5829,5834],{"__ignoreMap":3978},[3982,5688,5689,5692,5695],{"class":3984,"line":3985},[3982,5690,5691],{"class":3988},"function",[3982,5693,5694],{"class":5253}," TripsList",[3982,5696,5493],{"class":3996},[3982,5698,5699,5701,5703,5705,5708],{"class":3984,"line":4000},[3982,5700,5498],{"class":3988},[3982,5702,5670],{"class":5239},[3982,5704,5243],{"class":3996},[3982,5706,5707],{"class":5253},"useNetworkStatus",[3982,5709,5257],{"class":3996},[3982,5711,5712],{"class":3984,"line":4020},[3982,5713,4832],{"emptyLinePlaceholder":4831},[3982,5715,5716,5718],{"class":3984,"line":4046},[3982,5717,5667],{"class":5210},[3982,5719,5720],{"class":3996}," (\n",[3982,5722,5723,5726,5729],{"class":3984,"line":4069},[3982,5724,5725],{"class":3996},"    \u003C",[3982,5727,5728],{"class":3992},"View",[3982,5730,5731],{"class":3996},">\n",[3982,5733,5734,5737,5739],{"class":3984,"line":4086},[3982,5735,5736],{"class":3996},"      {!",[3982,5738,5504],{"class":4003},[3982,5740,5741],{"class":3996}," && (\n",[3982,5743,5744,5747,5750,5753,5756,5759],{"class":3984,"line":4103},[3982,5745,5746],{"class":3996},"        \u003C",[3982,5748,5749],{"class":4003},"Banner",[3982,5751,5752],{"class":4003}," variant",[3982,5754,5755],{"class":3996},"=",[3982,5757,5758],{"class":4028},"\"warning\"",[3982,5760,5731],{"class":3996},[3982,5762,5763,5766,5769,5772,5775,5778,5781,5784,5787,5790,5793],{"class":3984,"line":4119},[3982,5764,5765],{"class":4003},"          Офлайн",[3982,5767,5768],{"class":3996},"-",[3982,5770,5771],{"class":4003},"режим",[3982,5773,5774],{"class":3996},". ",[3982,5776,5777],{"class":4003},"Зміни",[3982,5779,5780],{"class":4003}," синхронізуються",[3982,5782,5783],{"class":4003}," автоматично",[3982,5785,5786],{"class":4003}," при",[3982,5788,5789],{"class":4003}," появі",[3982,5791,5792],{"class":4003}," мережі",[3982,5794,5795],{"class":3996},".\n",[3982,5797,5798,5801,5803],{"class":3984,"line":4135},[3982,5799,5800],{"class":3996},"        \u003C\u002F",[3982,5802,5749],{"class":4003},[3982,5804,5731],{"class":3996},[3982,5806,5807],{"class":3984,"line":4859},[3982,5808,5809],{"class":3996},"      )}\n",[3982,5811,5812,5815,5818],{"class":3984,"line":4865},[3982,5813,5814],{"class":3996},"      {",[3982,5816,5817],{"class":4016},"\u002F* список поїздок *\u002F",[3982,5819,4852],{"class":3996},[3982,5821,5822,5825,5827],{"class":3984,"line":4871},[3982,5823,5824],{"class":3996},"    \u003C\u002F",[3982,5826,5728],{"class":4003},[3982,5828,5731],{"class":3996},[3982,5830,5831],{"class":3984,"line":4877},[3982,5832,5833],{"class":3996},"  );\n",[3982,5835,5836],{"class":3984,"line":4883},[3982,5837,4852],{"class":3996},[4421,5839,5840,5843,5844,5847,5848,5851,5852,5855],{},[3747,5841,5842],{},"NetInfo на емуляторі:"," емулятор зазвичай завжди показує ",[3780,5845,5846],{},"isConnected: true",", навіть якщо на комп'ютері немає інтернету (він бачить локальну мережу). Щоб перевірити offline UX на емуляторі, вимкніть Wi-Fi в налаштуваннях ",[3747,5849,5850],{},"емульованого пристрою"," (Settings → Wi-Fi → Off у симуляторі iOS; або через ",[3780,5853,5854],{},"adb shell"," на Android).",[3836,5857],{},[3743,5859,5860,5861,5864],{},"Це ",[3747,5862,5863],{},"перша частина теорії"," (розділи 1.1–1.7). Продовжити з:",[3762,5866,5867,5870,5873,5876],{},[3765,5868,5869],{},"1.8. Exponential Backoff — розумні повторні спроби",[3765,5871,5872],{},"1.9. Batch Sync — об'єднання операцій",[3765,5874,5875],{},"1.10. Порівняння підходів (таблиця)",[3765,5877,5878],{},"Потім міні-проєкт + Nomad",[3743,5880,5881],{},"Чи продовжувати далі теорію, чи перейти до наступної секції?",[3843,5883,5869],{"id":5884},"_18-exponential-backoff-розумні-повторні-спроби",[3743,5886,5887,5888,5891,5892,5895,5896,5899],{},"Коли запит на сервер не вдається (timeout, 500, 503), застосунок має спробувати ще раз — але ",[3747,5889,5890],{},"не одразу",". Якщо сервер перевантажений або мережа нестабільна, миттєвий retry лише погіршить ситуацію. Замість цього використовують ",[3747,5893,5894],{},"exponential backoff"," (експоненційна затримка) — кожна наступна спроба відбувається через ",[3747,5897,5898],{},"удвічі довший"," інтервал.",[3743,5901,5902],{},[3747,5903,5904],{},"Приклад:",[3862,5906,5907,5920],{},[3865,5908,5909],{},[3868,5910,5911,5914,5917],{},[3871,5912,5913],{},"Спроба",[3871,5915,5916],{},"Затримка перед спробою",[3871,5918,5919],{},"Що сталося",[3878,5921,5922,5933,5944,5954],{},[3868,5923,5924,5927,5930],{},[3883,5925,5926],{},"1",[3883,5928,5929],{},"0 с (одразу)",[3883,5931,5932],{},"Timeout → помилка",[3868,5934,5935,5938,5941],{},[3883,5936,5937],{},"2",[3883,5939,5940],{},"2 с",[3883,5942,5943],{},"500 Server Error → помилка",[3868,5945,5946,5949,5952],{},[3883,5947,5948],{},"3",[3883,5950,5951],{},"4 с",[3883,5953,5932],{},[3868,5955,5956,5959,5962],{},[3883,5957,5958],{},"4",[3883,5960,5961],{},"8 с",[3883,5963,5964],{},"200 OK → успіх!",[3743,5966,5967],{},[3747,5968,5969],{},"Формула:",[3973,5971,5973],{"className":3975,"code":5972,"language":3977,"meta":3978,"style":3978},"const delay = Math.min(\n  baseDelay * Math.pow(2, retryCount),\n  maxDelay\n);\n",[3780,5974,5975,5995,6022,6027],{"__ignoreMap":3978},[3982,5976,5977,5979,5982,5984,5987,5989,5992],{"class":3984,"line":3985},[3982,5978,5236],{"class":3988},[3982,5980,5981],{"class":5239}," delay",[3982,5983,5243],{"class":3996},[3982,5985,5986],{"class":4003},"Math",[3982,5988,3823],{"class":3996},[3982,5990,5991],{"class":5253},"min",[3982,5993,5994],{"class":3996},"(\n",[3982,5996,5997,6000,6003,6005,6007,6010,6012,6015,6017,6019],{"class":3984,"line":4000},[3982,5998,5999],{"class":4003},"  baseDelay",[3982,6001,6002],{"class":3996}," * ",[3982,6004,5986],{"class":4003},[3982,6006,3823],{"class":3996},[3982,6008,6009],{"class":5253},"pow",[3982,6011,5270],{"class":3996},[3982,6013,5937],{"class":6014},"sJj4R",[3982,6016,3783],{"class":3996},[3982,6018,4189],{"class":4003},[3982,6020,6021],{"class":3996},"),\n",[3982,6023,6024],{"class":3984,"line":4020},[3982,6025,6026],{"class":4003},"  maxDelay\n",[3982,6028,6029],{"class":3984,"line":4046},[3982,6030,5375],{"class":3996},[3762,6032,6033,6039,6044],{},[3765,6034,6035,6038],{},[3780,6036,6037],{},"baseDelay"," — початкова затримка (наприклад, 2 секунди).",[3765,6040,6041,6043],{},[3780,6042,4189],{}," — номер спроби (0, 1, 2, 3, …).",[3765,6045,6046,6049],{},[3780,6047,6048],{},"maxDelay"," — максимальна затримка (наприклад, 60 секунд), щоб не чекати годинами.",[3743,6051,6052],{},[3747,6053,6054],{},"Реалізація в sync-worker:",[3973,6056,6058],{"className":3975,"code":6057,"language":3977,"meta":3978,"style":3978},"async function retrySyncItem(item: OutboxItem) {\n  const baseDelay = 2000; \u002F\u002F 2 секунди\n  const maxDelay = 60000; \u002F\u002F 60 секунд\n  const delay = Math.min(\n    baseDelay * Math.pow(2, item.retryCount),\n    maxDelay\n  );\n\n  await new Promise(resolve => setTimeout(resolve, delay));\n\n  try {\n    const response = await fetch(`\u002Fapi\u002F${item.resource}`, {\n      method: item.operation === 'CREATE' ? 'POST' : 'PATCH',\n      body: JSON.stringify(item.payload),\n    });\n\n    if (response.ok) {\n      \u002F\u002F Успіх — видалити з outbox\n      await db.outbox.delete(item.id);\n      await db.trips.update(item.payload.id, { syncStatus: 'synced' });\n    } else {\n      \u002F\u002F Помилка — збільшити retryCount\n      await db.outbox.update(item.id, {\n        retryCount: item.retryCount + 1,\n        lastError: await response.text(),\n      });\n    }\n  } catch (error) {\n    \u002F\u002F Мережева помилка — збільшити retryCount\n    await db.outbox.update(item.id, {\n      retryCount: item.retryCount + 1,\n      lastError: error.message,\n    });\n  }\n}\n",[3780,6059,6060,6082,6100,6117,6133,6160,6165,6169,6173,6205,6209,6216,6255,6288,6312,6316,6320,6337,6342,6369,6409,6418,6423,6447,6465,6483,6488,6493,6506,6511,6536,6553,6568,6572,6576],{"__ignoreMap":3978},[3982,6061,6062,6065,6067,6070,6072,6075,6077,6080],{"class":3984,"line":3985},[3982,6063,6064],{"class":3988},"async",[3982,6066,5487],{"class":3988},[3982,6068,6069],{"class":5253}," retrySyncItem",[3982,6071,5270],{"class":3996},[3982,6073,6074],{"class":4003},"item",[3982,6076,4007],{"class":3996},[3982,6078,6079],{"class":3992},"OutboxItem",[3982,6081,5358],{"class":3996},[3982,6083,6084,6086,6089,6091,6094,6097],{"class":3984,"line":4000},[3982,6085,5498],{"class":3988},[3982,6087,6088],{"class":5239}," baseDelay",[3982,6090,5243],{"class":3996},[3982,6092,6093],{"class":6014},"2000",[3982,6095,6096],{"class":3996},"; ",[3982,6098,6099],{"class":4016},"\u002F\u002F 2 секунди\n",[3982,6101,6102,6104,6107,6109,6112,6114],{"class":3984,"line":4020},[3982,6103,5498],{"class":3988},[3982,6105,6106],{"class":5239}," maxDelay",[3982,6108,5243],{"class":3996},[3982,6110,6111],{"class":6014},"60000",[3982,6113,6096],{"class":3996},[3982,6115,6116],{"class":4016},"\u002F\u002F 60 секунд\n",[3982,6118,6119,6121,6123,6125,6127,6129,6131],{"class":3984,"line":4046},[3982,6120,5498],{"class":3988},[3982,6122,5981],{"class":5239},[3982,6124,5243],{"class":3996},[3982,6126,5986],{"class":4003},[3982,6128,3823],{"class":3996},[3982,6130,5991],{"class":5253},[3982,6132,5994],{"class":3996},[3982,6134,6135,6138,6140,6142,6144,6146,6148,6150,6152,6154,6156,6158],{"class":3984,"line":4069},[3982,6136,6137],{"class":4003},"    baseDelay",[3982,6139,6002],{"class":3996},[3982,6141,5986],{"class":4003},[3982,6143,3823],{"class":3996},[3982,6145,6009],{"class":5253},[3982,6147,5270],{"class":3996},[3982,6149,5937],{"class":6014},[3982,6151,3783],{"class":3996},[3982,6153,6074],{"class":4003},[3982,6155,3823],{"class":3996},[3982,6157,4189],{"class":4003},[3982,6159,6021],{"class":3996},[3982,6161,6162],{"class":3984,"line":4086},[3982,6163,6164],{"class":4003},"    maxDelay\n",[3982,6166,6167],{"class":3984,"line":4103},[3982,6168,5833],{"class":3996},[3982,6170,6171],{"class":3984,"line":4119},[3982,6172,4832],{"emptyLinePlaceholder":4831},[3982,6174,6175,6178,6181,6184,6186,6189,6191,6194,6196,6198,6200,6203],{"class":3984,"line":4135},[3982,6176,6177],{"class":5210},"  await",[3982,6179,6180],{"class":3988}," new",[3982,6182,6183],{"class":3992}," Promise",[3982,6185,5270],{"class":3996},[3982,6187,6188],{"class":4003},"resolve",[3982,6190,5339],{"class":3988},[3982,6192,6193],{"class":5253}," setTimeout",[3982,6195,5270],{"class":3996},[3982,6197,6188],{"class":4003},[3982,6199,3783],{"class":3996},[3982,6201,6202],{"class":4003},"delay",[3982,6204,5584],{"class":3996},[3982,6206,6207],{"class":3984,"line":4859},[3982,6208,4832],{"emptyLinePlaceholder":4831},[3982,6210,6211,6214],{"class":3984,"line":4865},[3982,6212,6213],{"class":5210},"  try",[3982,6215,5342],{"class":3996},[3982,6217,6218,6220,6223,6225,6227,6230,6232,6235,6238,6240,6243,6246,6249,6252],{"class":3984,"line":4871},[3982,6219,5598],{"class":3988},[3982,6221,6222],{"class":5239}," response",[3982,6224,5243],{"class":3996},[3982,6226,5246],{"class":5210},[3982,6228,6229],{"class":5253}," fetch",[3982,6231,5270],{"class":3996},[3982,6233,6234],{"class":4028},"`\u002Fapi\u002F",[3982,6236,6237],{"class":3988},"${",[3982,6239,6074],{"class":4003},[3982,6241,3823],{"class":6242},"sD7JJ",[3982,6244,6245],{"class":4003},"resource",[3982,6247,6248],{"class":3988},"}",[3982,6250,6251],{"class":4028},"`",[3982,6253,6254],{"class":3996},", {\n",[3982,6256,6257,6260,6263,6265,6268,6271,6273,6276,6279,6282,6285],{"class":3984,"line":4877},[3982,6258,6259],{"class":4003},"      method:",[3982,6261,6262],{"class":4003}," item",[3982,6264,3823],{"class":3996},[3982,6266,6267],{"class":4003},"operation",[3982,6269,6270],{"class":3996}," === ",[3982,6272,4029],{"class":4028},[3982,6274,6275],{"class":3996}," ? ",[3982,6277,6278],{"class":4028},"'POST'",[3982,6280,6281],{"class":3996}," : ",[3982,6283,6284],{"class":4028},"'PATCH'",[3982,6286,6287],{"class":3996},",\n",[3982,6289,6290,6293,6296,6298,6301,6303,6305,6307,6310],{"class":3984,"line":4883},[3982,6291,6292],{"class":4003},"      body:",[3982,6294,6295],{"class":5239}," JSON",[3982,6297,3823],{"class":3996},[3982,6299,6300],{"class":5253},"stringify",[3982,6302,5270],{"class":3996},[3982,6304,6074],{"class":4003},[3982,6306,3823],{"class":3996},[3982,6308,6309],{"class":4003},"payload",[3982,6311,6021],{"class":3996},[3982,6313,6314],{"class":3984,"line":4888},[3982,6315,5640],{"class":3996},[3982,6317,6318],{"class":3984,"line":4893},[3982,6319,4832],{"emptyLinePlaceholder":4831},[3982,6321,6322,6325,6327,6330,6332,6335],{"class":3984,"line":4899},[3982,6323,6324],{"class":5210},"    if",[3982,6326,3778],{"class":3996},[3982,6328,6329],{"class":4003},"response",[3982,6331,3823],{"class":3996},[3982,6333,6334],{"class":4003},"ok",[3982,6336,5358],{"class":3996},[3982,6338,6339],{"class":3984,"line":4905},[3982,6340,6341],{"class":4016},"      \u002F\u002F Успіх — видалити з outbox\n",[3982,6343,6344,6347,6350,6352,6354,6356,6359,6361,6363,6365,6367],{"class":3984,"line":4911},[3982,6345,6346],{"class":5210},"      await",[3982,6348,6349],{"class":4003}," db",[3982,6351,3823],{"class":3996},[3982,6353,4157],{"class":4003},[3982,6355,3823],{"class":3996},[3982,6357,6358],{"class":5253},"delete",[3982,6360,5270],{"class":3996},[3982,6362,6074],{"class":4003},[3982,6364,3823],{"class":3996},[3982,6366,5166],{"class":4003},[3982,6368,5375],{"class":3996},[3982,6370,6371,6373,6375,6377,6380,6382,6385,6387,6389,6391,6393,6395,6397,6400,6403,6406],{"class":3984,"line":4916},[3982,6372,6346],{"class":5210},[3982,6374,6349],{"class":4003},[3982,6376,3823],{"class":3996},[3982,6378,6379],{"class":4003},"trips",[3982,6381,3823],{"class":3996},[3982,6383,6384],{"class":5253},"update",[3982,6386,5270],{"class":3996},[3982,6388,6074],{"class":4003},[3982,6390,3823],{"class":3996},[3982,6392,6309],{"class":4003},[3982,6394,3823],{"class":3996},[3982,6396,5166],{"class":4003},[3982,6398,6399],{"class":3996},", { ",[3982,6401,6402],{"class":4003},"syncStatus:",[3982,6404,6405],{"class":4028}," 'synced'",[3982,6407,6408],{"class":3996}," });\n",[3982,6410,6411,6414,6416],{"class":3984,"line":4921},[3982,6412,6413],{"class":3996},"    } ",[3982,6415,5395],{"class":5210},[3982,6417,5342],{"class":3996},[3982,6419,6420],{"class":3984,"line":4927},[3982,6421,6422],{"class":4016},"      \u002F\u002F Помилка — збільшити retryCount\n",[3982,6424,6425,6427,6429,6431,6433,6435,6437,6439,6441,6443,6445],{"class":3984,"line":4933},[3982,6426,6346],{"class":5210},[3982,6428,6349],{"class":4003},[3982,6430,3823],{"class":3996},[3982,6432,4157],{"class":4003},[3982,6434,3823],{"class":3996},[3982,6436,6384],{"class":5253},[3982,6438,5270],{"class":3996},[3982,6440,6074],{"class":4003},[3982,6442,3823],{"class":3996},[3982,6444,5166],{"class":4003},[3982,6446,6254],{"class":3996},[3982,6448,6449,6452,6454,6456,6458,6461,6463],{"class":3984,"line":4938},[3982,6450,6451],{"class":4003},"        retryCount:",[3982,6453,6262],{"class":4003},[3982,6455,3823],{"class":3996},[3982,6457,4189],{"class":4003},[3982,6459,6460],{"class":3996}," + ",[3982,6462,5926],{"class":6014},[3982,6464,6287],{"class":3996},[3982,6466,6467,6470,6473,6475,6477,6480],{"class":3984,"line":4943},[3982,6468,6469],{"class":4003},"        lastError:",[3982,6471,6472],{"class":5210}," await",[3982,6474,6222],{"class":4003},[3982,6476,3823],{"class":3996},[3982,6478,6479],{"class":5253},"text",[3982,6481,6482],{"class":3996},"(),\n",[3982,6484,6485],{"class":3984,"line":4949},[3982,6486,6487],{"class":3996},"      });\n",[3982,6489,6490],{"class":3984,"line":4954},[3982,6491,6492],{"class":3996},"    }\n",[3982,6494,6495,6497,6500,6502,6504],{"class":3984,"line":4960},[3982,6496,5392],{"class":3996},[3982,6498,6499],{"class":5210},"catch",[3982,6501,3778],{"class":3996},[3982,6503,3789],{"class":4003},[3982,6505,5358],{"class":3996},[3982,6507,6508],{"class":3984,"line":4966},[3982,6509,6510],{"class":4016},"    \u002F\u002F Мережева помилка — збільшити retryCount\n",[3982,6512,6513,6516,6518,6520,6522,6524,6526,6528,6530,6532,6534],{"class":3984,"line":4972},[3982,6514,6515],{"class":5210},"    await",[3982,6517,6349],{"class":4003},[3982,6519,3823],{"class":3996},[3982,6521,4157],{"class":4003},[3982,6523,3823],{"class":3996},[3982,6525,6384],{"class":5253},[3982,6527,5270],{"class":3996},[3982,6529,6074],{"class":4003},[3982,6531,3823],{"class":3996},[3982,6533,5166],{"class":4003},[3982,6535,6254],{"class":3996},[3982,6537,6538,6541,6543,6545,6547,6549,6551],{"class":3984,"line":4978},[3982,6539,6540],{"class":4003},"      retryCount:",[3982,6542,6262],{"class":4003},[3982,6544,3823],{"class":3996},[3982,6546,4189],{"class":4003},[3982,6548,6460],{"class":3996},[3982,6550,5926],{"class":6014},[3982,6552,6287],{"class":3996},[3982,6554,6555,6558,6561,6563,6566],{"class":3984,"line":4983},[3982,6556,6557],{"class":4003},"      lastError:",[3982,6559,6560],{"class":4003}," error",[3982,6562,3823],{"class":3996},[3982,6564,6565],{"class":4003},"message",[3982,6567,6287],{"class":3996},[3982,6569,6570],{"class":3984,"line":4989},[3982,6571,5640],{"class":3996},[3982,6573,6574],{"class":3984,"line":4995},[3982,6575,5417],{"class":3996},[3982,6577,6578],{"class":3984,"line":5001},[3982,6579,4852],{"class":3996},[3743,6581,6582],{},[3747,6583,6584],{},"Навіщо це потрібно:",[3762,6586,6587,6593,6599],{},[3765,6588,6589,6592],{},[3747,6590,6591],{},"Зменшує навантаження на сервер:"," якщо сервер недоступний, тисячі пристроїв не бомбардують його запитами кожної секунди.",[3765,6594,6595,6598],{},[3747,6596,6597],{},"Економить батарею:"," менше мережевих запитів — менше радіо-активності.",[3765,6600,6601,6604],{},[3747,6602,6603],{},"Збільшує шанс успіху:"," якщо проблема тимчасова (перезапуск сервера, короткочасна втрата мережі), retry через кілька секунд\u002Fхвилин часто допомагає.",[3825,6606,6607,6610],{},[3747,6608,6609],{},"Exponential backoff"," — це стратегія повторних спроб, де затримка між спробами зростає експоненційно (2 с, 4 с, 8 с, 16 с, …). Це зменшує навантаження на сервер і батарею, даючи час системі відновитися.",[3743,6612,6613],{},[3747,6614,6615],{},"Додаткова техніка: jitter (дрижання):",[3743,6617,6618,6619,6622,6623,6626],{},"Якщо всі пристрої одночасно отримали помилку (наприклад, сервер упав на 10 секунд), вони ",[3747,6620,6621],{},"синхронно"," спробують retry через 2 с, 4 с, 8 с — і знову створять пік навантаження. Щоб цього уникнути, додають ",[3747,6624,6625],{},"випадковий зсув"," (jitter):",[3973,6628,6630],{"className":3975,"code":6629,"language":3977,"meta":3978,"style":3978},"const jitter = Math.random() * 1000; \u002F\u002F 0–1000 мс\nconst delay = Math.min(\n  baseDelay * Math.pow(2, retryCount) + jitter,\n  maxDelay\n);\n",[3780,6631,6632,6659,6675,6703,6707],{"__ignoreMap":3978},[3982,6633,6634,6636,6639,6641,6643,6645,6648,6651,6654,6656],{"class":3984,"line":3985},[3982,6635,5236],{"class":3988},[3982,6637,6638],{"class":5239}," jitter",[3982,6640,5243],{"class":3996},[3982,6642,5986],{"class":4003},[3982,6644,3823],{"class":3996},[3982,6646,6647],{"class":5253},"random",[3982,6649,6650],{"class":3996},"() * ",[3982,6652,6653],{"class":6014},"1000",[3982,6655,6096],{"class":3996},[3982,6657,6658],{"class":4016},"\u002F\u002F 0–1000 мс\n",[3982,6660,6661,6663,6665,6667,6669,6671,6673],{"class":3984,"line":4000},[3982,6662,5236],{"class":3988},[3982,6664,5981],{"class":5239},[3982,6666,5243],{"class":3996},[3982,6668,5986],{"class":4003},[3982,6670,3823],{"class":3996},[3982,6672,5991],{"class":5253},[3982,6674,5994],{"class":3996},[3982,6676,6677,6679,6681,6683,6685,6687,6689,6691,6693,6695,6698,6701],{"class":3984,"line":4020},[3982,6678,5999],{"class":4003},[3982,6680,6002],{"class":3996},[3982,6682,5986],{"class":4003},[3982,6684,3823],{"class":3996},[3982,6686,6009],{"class":5253},[3982,6688,5270],{"class":3996},[3982,6690,5937],{"class":6014},[3982,6692,3783],{"class":3996},[3982,6694,4189],{"class":4003},[3982,6696,6697],{"class":3996},") + ",[3982,6699,6700],{"class":4003},"jitter",[3982,6702,6287],{"class":3996},[3982,6704,6705],{"class":3984,"line":4046},[3982,6706,6026],{"class":4003},[3982,6708,6709],{"class":3984,"line":4069},[3982,6710,5375],{"class":3996},[3743,6712,6713],{},"Тепер кожен пристрій чекає трохи по-різному — навантаження розподіляється в часі.",[3836,6715],{},[3843,6717,5872],{"id":6718},"_19-batch-sync-обєднання-операцій",[3743,6720,6721,6722,3823],{},"Якщо користувач офлайн створив 10 поїздок і 20 місць, то в outbox буде 30 записів. Відправляти їх по одному — 30 окремих HTTP-запитів — повільно і витратно для батареї. Замість цього можна ",[3747,6723,6724],{},"об'єднати кілька операцій в один batch-запит",[3743,6726,6727],{},[3747,6728,6729],{},"Приклад batch API:",[3973,6731,6735],{"className":6732,"code":6733,"language":6734,"meta":3978,"style":3978},"language-http shiki shiki-themes light-plus dark-plus dark-plus","POST \u002Fapi\u002Fsync\u002Fbatch\nContent-Type: application\u002Fjson\n\n{\n  \"operations\": [\n    { \"op\": \"CREATE\", \"resource\": \"trip\", \"localId\": \"local-1\", \"data\": { \"title\": \"Київ\" } },\n    { \"op\": \"CREATE\", \"resource\": \"trip\", \"localId\": \"local-2\", \"data\": { \"title\": \"Львів\" } },\n    { \"op\": \"UPDATE\", \"resource\": \"place\", \"serverId\": \"place-42\", \"data\": { \"name\": \"Майдан\" } }\n  ]\n}\n","http",[3780,6736,6737,6745,6757,6761,6766,6775,6826,6868,6915,6920],{"__ignoreMap":3978},[3982,6738,6739,6742],{"class":3984,"line":3985},[3982,6740,6741],{"class":5210},"POST",[3982,6743,6744],{"class":3996}," \u002Fapi\u002Fsync\u002Fbatch\n",[3982,6746,6747,6751,6754],{"class":3984,"line":4000},[3982,6748,6750],{"class":6749},"sKtos","Content-Type",[3982,6752,6753],{"class":3988},":",[3982,6755,6756],{"class":4028}," application\u002Fjson\n",[3982,6758,6759],{"class":3984,"line":4020},[3982,6760,4832],{"emptyLinePlaceholder":4831},[3982,6762,6763],{"class":3984,"line":4046},[3982,6764,6765],{"class":3996},"{\n",[3982,6767,6768,6772],{"class":3984,"line":4069},[3982,6769,6771],{"class":6770},"sLwNe","  \"operations\"",[3982,6773,6774],{"class":3996},": [\n",[3982,6776,6777,6780,6783,6785,6788,6790,6793,6795,6798,6800,6803,6805,6808,6810,6813,6816,6819,6821,6823],{"class":3984,"line":4086},[3982,6778,6779],{"class":3996},"    { ",[3982,6781,6782],{"class":6770},"\"op\"",[3982,6784,4007],{"class":3996},[3982,6786,6787],{"class":4028},"\"CREATE\"",[3982,6789,3783],{"class":3996},[3982,6791,6792],{"class":6770},"\"resource\"",[3982,6794,4007],{"class":3996},[3982,6796,6797],{"class":4028},"\"trip\"",[3982,6799,3783],{"class":3996},[3982,6801,6802],{"class":6770},"\"localId\"",[3982,6804,4007],{"class":3996},[3982,6806,6807],{"class":4028},"\"local-1\"",[3982,6809,3783],{"class":3996},[3982,6811,6812],{"class":6770},"\"data\"",[3982,6814,6815],{"class":3996},": { ",[3982,6817,6818],{"class":6770},"\"title\"",[3982,6820,4007],{"class":3996},[3982,6822,4594],{"class":4028},[3982,6824,6825],{"class":3996}," } },\n",[3982,6827,6828,6830,6832,6834,6836,6838,6840,6842,6844,6846,6848,6850,6853,6855,6857,6859,6861,6863,6866],{"class":3984,"line":4103},[3982,6829,6779],{"class":3996},[3982,6831,6782],{"class":6770},[3982,6833,4007],{"class":3996},[3982,6835,6787],{"class":4028},[3982,6837,3783],{"class":3996},[3982,6839,6792],{"class":6770},[3982,6841,4007],{"class":3996},[3982,6843,6797],{"class":4028},[3982,6845,3783],{"class":3996},[3982,6847,6802],{"class":6770},[3982,6849,4007],{"class":3996},[3982,6851,6852],{"class":4028},"\"local-2\"",[3982,6854,3783],{"class":3996},[3982,6856,6812],{"class":6770},[3982,6858,6815],{"class":3996},[3982,6860,6818],{"class":6770},[3982,6862,4007],{"class":3996},[3982,6864,6865],{"class":4028},"\"Львів\"",[3982,6867,6825],{"class":3996},[3982,6869,6870,6872,6874,6876,6879,6881,6883,6885,6888,6890,6893,6895,6898,6900,6902,6904,6907,6909,6912],{"class":3984,"line":4119},[3982,6871,6779],{"class":3996},[3982,6873,6782],{"class":6770},[3982,6875,4007],{"class":3996},[3982,6877,6878],{"class":4028},"\"UPDATE\"",[3982,6880,3783],{"class":3996},[3982,6882,6792],{"class":6770},[3982,6884,4007],{"class":3996},[3982,6886,6887],{"class":4028},"\"place\"",[3982,6889,3783],{"class":3996},[3982,6891,6892],{"class":6770},"\"serverId\"",[3982,6894,4007],{"class":3996},[3982,6896,6897],{"class":4028},"\"place-42\"",[3982,6899,3783],{"class":3996},[3982,6901,6812],{"class":6770},[3982,6903,6815],{"class":3996},[3982,6905,6906],{"class":6770},"\"name\"",[3982,6908,4007],{"class":3996},[3982,6910,6911],{"class":4028},"\"Майдан\"",[3982,6913,6914],{"class":3996}," } }\n",[3982,6916,6917],{"class":3984,"line":4135},[3982,6918,6919],{"class":3996},"  ]\n",[3982,6921,6922],{"class":3984,"line":4859},[3982,6923,4852],{"class":3996},[3743,6925,6926],{},[3747,6927,6928],{},"Відповідь сервера:",[3973,6930,6934],{"className":6931,"code":6932,"language":6933,"meta":3978,"style":3978},"language-json shiki shiki-themes light-plus dark-plus dark-plus","{\n  \"results\": [\n    { \"localId\": \"local-1\", \"status\": \"success\", \"serverId\": \"srv-101\" },\n    { \"localId\": \"local-2\", \"status\": \"success\", \"serverId\": \"srv-102\" },\n    { \"serverId\": \"place-42\", \"status\": \"success\" }\n  ]\n}\n","json",[3780,6935,6936,6940,6947,6979,7008,7029,7033],{"__ignoreMap":3978},[3982,6937,6938],{"class":3984,"line":3985},[3982,6939,6765],{"class":3996},[3982,6941,6942,6945],{"class":3984,"line":4000},[3982,6943,6944],{"class":6770},"  \"results\"",[3982,6946,6774],{"class":3996},[3982,6948,6949,6951,6953,6955,6957,6959,6962,6964,6967,6969,6971,6973,6976],{"class":3984,"line":4020},[3982,6950,6779],{"class":3996},[3982,6952,6802],{"class":6770},[3982,6954,4007],{"class":3996},[3982,6956,6807],{"class":4028},[3982,6958,3783],{"class":3996},[3982,6960,6961],{"class":6770},"\"status\"",[3982,6963,4007],{"class":3996},[3982,6965,6966],{"class":4028},"\"success\"",[3982,6968,3783],{"class":3996},[3982,6970,6892],{"class":6770},[3982,6972,4007],{"class":3996},[3982,6974,6975],{"class":4028},"\"srv-101\"",[3982,6977,6978],{"class":3996}," },\n",[3982,6980,6981,6983,6985,6987,6989,6991,6993,6995,6997,6999,7001,7003,7006],{"class":3984,"line":4046},[3982,6982,6779],{"class":3996},[3982,6984,6802],{"class":6770},[3982,6986,4007],{"class":3996},[3982,6988,6852],{"class":4028},[3982,6990,3783],{"class":3996},[3982,6992,6961],{"class":6770},[3982,6994,4007],{"class":3996},[3982,6996,6966],{"class":4028},[3982,6998,3783],{"class":3996},[3982,7000,6892],{"class":6770},[3982,7002,4007],{"class":3996},[3982,7004,7005],{"class":4028},"\"srv-102\"",[3982,7007,6978],{"class":3996},[3982,7009,7010,7012,7014,7016,7018,7020,7022,7024,7026],{"class":3984,"line":4069},[3982,7011,6779],{"class":3996},[3982,7013,6892],{"class":6770},[3982,7015,4007],{"class":3996},[3982,7017,6897],{"class":4028},[3982,7019,3783],{"class":3996},[3982,7021,6961],{"class":6770},[3982,7023,4007],{"class":3996},[3982,7025,6966],{"class":4028},[3982,7027,7028],{"class":3996}," }\n",[3982,7030,7031],{"class":3984,"line":4086},[3982,7032,6919],{"class":3996},[3982,7034,7035],{"class":3984,"line":4103},[3982,7036,4852],{"class":3996},[3743,7038,7039],{},[3747,7040,7041],{},"Переваги batch sync:",[3762,7043,7044,7050,7056],{},[3765,7045,7046,7049],{},[3747,7047,7048],{},"Швидше:"," один TCP-handshake замість 30.",[3765,7051,7052,7055],{},[3747,7053,7054],{},"Менше батареї:"," радіо-модуль активний коротший час.",[3765,7057,7058,7061],{},[3747,7059,7060],{},"Атомарність:"," сервер може обробити всі операції в одній транзакції (або відкотити всі, якщо щось не так).",[3743,7063,7064],{},[3747,7065,7066],{},"Коли використовувати:",[3762,7068,7069,7075],{},[3765,7070,7071,7074],{},[3747,7072,7073],{},"Багато дрібних змін:"," користувач швидко створив 5 поїздок — краще відправити batch.",[3765,7076,7077,7080],{},[3747,7078,7079],{},"Періодична синхронізація:"," раз на хвилину збирати всі pending-операції і відправляти одним пакетом.",[3743,7082,7083],{},[3747,7084,7085],{},"Коли не використовувати:",[3762,7087,7088,7097],{},[3765,7089,7090,7093,7094,7096],{},[3747,7091,7092],{},"Критично важливі дані:"," якщо треба одразу отримати ",[3780,7095,4182],{}," (наприклад, для наступного запиту), краще відправити окремо.",[3765,7098,7099,7102,7103,7106],{},[3747,7100,7101],{},"Немає batch API:"," не всі сервери підтримують ",[3780,7104,7105],{},"\u002Fsync\u002Fbatch"," — тоді доводиться по одному.",[3743,7108,7109,7110,7112,7113,7116],{},"У ",[3747,7111,3814],{}," ми для простоти відправляємо операції ",[3747,7114,7115],{},"по одній",", але в реальному застосунку часто додають batch для оптимізації.",[3954,7118,7119,7122,7123,4471],{},[3747,7120,7121],{},"Batch sync"," — це відправка кількох операцій (CREATE, UPDATE, DELETE) в одному HTTP-запиті. Це швидше і економніше, але вимагає підтримки на сервері (endpoint ",[3780,7124,7105],{},[3836,7126],{},[3843,7128,7130],{"id":7129},"_110-порівняння-підходів-до-синхронізації","1.10. Порівняння підходів до синхронізації",[3743,7132,7133],{},"Є кілька стратегій організації offline-sync. Ось найпоширеніші:",[3862,7135,7136,7155],{},[3865,7137,7138],{},[3868,7139,7140,7143,7146,7149,7152],{},[3871,7141,7142],{},"Підхід",[3871,7144,7145],{},"Суть",[3871,7147,7148],{},"Переваги",[3871,7150,7151],{},"Недоліки",[3871,7153,7154],{},"Коли використовувати",[3878,7156,7157,7176,7195,7214,7233],{},[3868,7158,7159,7164,7167,7170,7173],{},[3883,7160,7161],{},[3747,7162,7163],{},"Outbox Pattern",[3883,7165,7166],{},"Локальна таблиця операцій; фоновий worker обробляє чергу",[3883,7168,7169],{},"Простий, гарантія доставки, працює без мережі",[3883,7171,7172],{},"Потребує окрему таблицю; складно з залежними операціями",[3883,7174,7175],{},"Більшість мобільних застосунків (TODO, CRM, notes)",[3868,7177,7178,7183,7186,7189,7192],{},[3883,7179,7180],{},[3747,7181,7182],{},"Event Sourcing",[3883,7184,7185],{},"Зберігає всі зміни як події (event log); сервер replay подій",[3883,7187,7188],{},"Повна історія, легко відкотити",[3883,7190,7191],{},"Складний, багато даних, потребує спеціальної архітектури сервера",[3883,7193,7194],{},"Фінтех, аудит-лог, collaborative editing",[3868,7196,7197,7202,7205,7208,7211],{},[3883,7198,7199],{},[3747,7200,7201],{},"CRDT (Conflict-Free Replicated Data Types)",[3883,7203,7204],{},"Автоматичне об'єднання змін без конфліктів",[3883,7206,7207],{},"Немає ручного merge, працює P2P",[3883,7209,7210],{},"Складний, не всі типи даних підтримує",[3883,7212,7213],{},"Collaborative editing (Figma, Google Docs), chat",[3868,7215,7216,7221,7224,7227,7230],{},[3883,7217,7218],{},[3747,7219,7220],{},"Polling (pull from server)",[3883,7222,7223],{},"Періодично завантажує всі дані з сервера, замінює локальні",[3883,7225,7226],{},"Простий, не потребує outbox",[3883,7228,7229],{},"Витратний (багато трафіку), затирає локальні pending-зміни",[3883,7231,7232],{},"Readonly-застосунки (новини, каталог)",[3868,7234,7235,7240,7243,7246,7249],{},[3883,7236,7237],{},[3747,7238,7239],{},"Firebase\u002FFirestore Sync",[3883,7241,7242],{},"Хмарна база з вбудованою синхронізацією",[3883,7244,7245],{},"Дуже простий (все «з коробки»), realtime",[3883,7247,7248],{},"Vendor lock-in, дорого при масштабі, обмежений query",[3883,7250,7251],{},"MVP, малі проєкти, realtime-чати",[3743,7253,7254,4558,7257,7259],{},[3747,7255,7256],{},"Для навчання",[3747,7258,7163],{}," — він найпоширеніший і добре пояснює базові принципи (черга, retry, syncStatus, conflicts). Інші підходи — це еволюція або спеціалізація цієї базової ідеї.",[3825,7261,7262,7264],{},[3747,7263,7163],{}," — найпростіший і найпоширеніший підхід для offline-first у мобільних застасунках. Він дає повний контроль над синхронізацією, не вимагає спеціальних серверних фреймворків і працює з будь-яким REST API.",[3836,7266],{},[3843,7268,7270],{"id":7269},"_111-коли-offline-first-не-потрібен","1.11. Коли offline-first не потрібен",[3743,7272,7273,7274,7277,7278,7281],{},"Не кожен застосунок має бути offline-first. Іноді простіше зробити ",[3747,7275,7276],{},"online-only"," (блокувати UI без мережі) або ",[3747,7279,7280],{},"readonly offline"," (показувати кешовані дані, але не дозволяти створювати нові).",[3743,7283,7284],{},[3747,7285,7286],{},"Не варто робити offline-first, якщо:",[3862,7288,7289,7299],{},[3865,7290,7291],{},[3868,7292,7293,7296],{},[3871,7294,7295],{},"Випадок",[3871,7297,7298],{},"Чому online-only достатньо",[3878,7300,7301,7311,7321,7331,7341],{},[3868,7302,7303,7308],{},[3883,7304,7305],{},[3747,7306,7307],{},"Критичні фінансові операції",[3883,7309,7310],{},"Потрібна миттєва перевірка балансу, fraud-detection — локальна черга ризикована.",[3868,7312,7313,7318],{},[3883,7314,7315],{},[3747,7316,7317],{},"Realtime collaboration",[3883,7319,7320],{},"Якщо 10 людей одночасно редагують документ, offline-зміни створюють складні конфлікти.",[3868,7322,7323,7328],{},[3883,7324,7325],{},[3747,7326,7327],{},"Дані з коротким TTL",[3883,7329,7330],{},"Курси валют, ціни акцій — через 5 хвилин дані застарілі, синхронізувати немає сенсу.",[3868,7332,7333,7338],{},[3883,7334,7335],{},[3747,7336,7337],{},"Readonly-контент",[3883,7339,7340],{},"Новини, каталог товарів — можна кешувати для читання, але створювати нічого не треба.",[3868,7342,7343,7348],{},[3883,7344,7345],{},[3747,7346,7347],{},"Прості форми з рідким використанням",[3883,7349,7350],{},"Якщо застосунок відкривають раз на місяць з Wi-Fi — складність offline-sync не окупається.",[3743,7352,7353,7356,7357,7360],{},[3747,7354,7355],{},"Для Nomad"," offline-first ",[3747,7358,7359],{},"доречний",", бо:",[3762,7362,7363,7366,7369],{},[3765,7364,7365],{},"Подорожі часто трапляються в місцях без мережі (літак, гори, закордон без роумінгу).",[3765,7367,7368],{},"Створення поїздки\u002Fмісця — проста операція, конфлікти рідкі.",[3765,7370,7371],{},"Користувач очікує, що щоденник «просто працює», як Notes на iPhone.",[3836,7373],{},[3738,7375,7377],{"id":7376},"частина-2-міні-проєкт-офлайн-чеклист","Частина 2. Міні-проєкт «Офлайн-чеклист»",[3743,7379,7380,7381,7384],{},"Тепер застосуємо теорію на практиці. Створимо ",[3747,7382,7383],{},"простий TODO-застосунок"," із синхронізацією:",[3762,7386,7387,7390,7395,7398,7401],{},[3765,7388,7389],{},"Користувач додає завдання (онлайн або офлайн).",[3765,7391,7392,7393,3823],{},"Якщо офлайн — завдання потрапляє в локальну чергу з ",[3780,7394,4151],{},[3765,7396,7397],{},"Фоновий worker періодично перевіряє мережу і відправляє pending-завдання на mock API.",[3765,7399,7400],{},"У списку біля кожного завдання — badge зі статусом синхронізації.",[3765,7402,7403],{},"При помилці — кнопка «Повторити».",[3743,7405,7406],{},[3747,7407,7408],{},"Стек:",[3762,7410,7411,7414,7416,7419,7422],{},[3765,7412,7413],{},"React Native (Expo)",[3765,7415,2325],{},[3765,7417,7418],{},"Zustand (для простоти, замість RTK)",[3765,7420,7421],{},"MMKV (локальне сховище)",[3765,7423,7424,7425,7428,7429,7431],{},"Mock API (JSON Placeholder або локальний express-сервер; для демо можна просто ",[3780,7426,7427],{},"setTimeout"," замість ",[3780,7430,5254],{},")",[3743,7433,7434],{},[3747,7435,7436],{},"Структура проєкту:",[7438,7439,7441,7449,7520,9091,9098,10048,10055,10261,10923],"code-tree",{"name":7440},"offline-checklist",[3973,7442,7447],{"className":7443,"code":7445,"filename":7446,"language":6479,"meta":3978},[7444],"language-text","app\u002F\n├── _layout.tsx\n└── index.tsx\n","app",[3780,7448,7445],{"__ignoreMap":3978},[3973,7450,7453],{"className":3975,"code":7451,"filename":7452,"language":3977,"meta":3978,"style":3978},"import { Stack } from 'expo-router';\n\nexport default function RootLayout() {\n  return \u003CStack screenOptions={{ headerShown: false }} \u002F>;\n}\n","app\u002F_layout.tsx",[3780,7454,7455,7473,7477,7491,7516],{"__ignoreMap":3978},[3982,7456,7457,7459,7461,7464,7466,7468,7471],{"class":3984,"line":3985},[3982,7458,5211],{"class":5210},[3982,7460,5444],{"class":3996},[3982,7462,7463],{"class":4003},"Stack",[3982,7465,5455],{"class":3996},[3982,7467,5458],{"class":5210},[3982,7469,7470],{"class":4028}," 'expo-router'",[3982,7472,4043],{"class":3996},[3982,7474,7475],{"class":3984,"line":4000},[3982,7476,4832],{"emptyLinePlaceholder":4831},[3982,7478,7479,7481,7484,7486,7489],{"class":3984,"line":4020},[3982,7480,5484],{"class":5210},[3982,7482,7483],{"class":5210}," default",[3982,7485,5487],{"class":3988},[3982,7487,7488],{"class":5253}," RootLayout",[3982,7490,5493],{"class":3996},[3982,7492,7493,7495,7498,7500,7503,7506,7509,7511,7513],{"class":3984,"line":4046},[3982,7494,5667],{"class":5210},[3982,7496,7497],{"class":3996}," \u003C",[3982,7499,7463],{"class":3992},[3982,7501,7502],{"class":3992}," screenOptions",[3982,7504,7505],{"class":3996},"={{ ",[3982,7507,7508],{"class":4003},"headerShown",[3982,7510,4007],{"class":3996},[3982,7512,5581],{"class":3992},[3982,7514,7515],{"class":3996}," }} \u002F>;\n",[3982,7517,7518],{"class":3984,"line":4069},[3982,7519,4852],{"class":3996},[3973,7521,7524],{"className":3975,"code":7522,"filename":7523,"language":3977,"meta":3978,"style":3978},"import { View, Text, TextInput, FlatList, Pressable, StyleSheet } from 'react-native';\nimport { useState, useEffect } from 'react';\nimport { useStore } from '..\u002Fstore\u002FuseStore';\nimport { useSyncWorker } from '..\u002Fhooks\u002FuseSyncWorker';\nimport { useNetworkStatus } from '..\u002Fhooks\u002FuseNetworkStatus';\n\nexport default function HomeScreen() {\n  const [text, setText] = useState('');\n  const { tasks, addTask, retrySync } = useStore();\n  const isOnline = useNetworkStatus();\n\n  useSyncWorker(); \u002F\u002F Запускає фонову синхронізацію\n\n  const handleAdd = () => {\n    if (text.trim()) {\n      addTask(text.trim());\n      setText('');\n    }\n  };\n\n  return (\n    \u003CView style={styles.container}>\n      {\u002F* Network banner *\u002F}\n      {!isOnline && (\n        \u003CView style={styles.banner}>\n          \u003CText style={styles.bannerText}>📡 Офлайн-режим\u003C\u002FText>\n        \u003C\u002FView>\n      )}\n\n      \u003CText style={styles.title}>Офлайн-чеклист\u003C\u002FText>\n\n      {\u002F* Input *\u002F}\n      \u003CView style={styles.inputRow}>\n        \u003CTextInput\n          style={styles.input}\n          placeholder=\"Нове завдання...\"\n          value={text}\n          onChangeText={setText}\n          onSubmitEditing={handleAdd}\n        \u002F>\n        \u003CPressable style={styles.addButton} onPress={handleAdd}>\n          \u003CText style={styles.addButtonText}>+\u003C\u002FText>\n        \u003C\u002FPressable>\n      \u003C\u002FView>\n\n      {\u002F* List *\u002F}\n      \u003CFlatList\n        data={tasks}\n        keyExtractor={(item) => item.id}\n        renderItem={({ item }) => (\n          \u003CView style={styles.taskCard}>\n            \u003CText style={styles.taskText}>{item.text}\u003C\u002FText>\n            \u003CView style={styles.taskFooter}>\n              {item.syncStatus === 'pending' && (\n                \u003CText style={styles.badge}>⏳ Не синхронізовано\u003C\u002FText>\n              )}\n              {item.syncStatus === 'syncing' && (\n                \u003CText style={[styles.badge, styles.badgeSyncing]}>🔄 Відправляється...\u003C\u002FText>\n              )}\n              {item.syncStatus === 'synced' && (\n                \u003CText style={[styles.badge, styles.badgeSynced]}>✅ Синхронізовано\u003C\u002FText>\n              )}\n              {item.syncStatus === 'error' && (\n                \u003CView style={styles.errorRow}>\n                  \u003CText style={[styles.badge, styles.badgeError]}>❌ Помилка\u003C\u002FText>\n                  \u003CPressable onPress={() => retrySync(item.id)}>\n                    \u003CText style={styles.retryButton}>Повторити\u003C\u002FText>\n                  \u003C\u002FPressable>\n                \u003C\u002FView>\n              )}\n            \u003C\u002FView>\n          \u003C\u002FView>\n        )}\n        contentContainerStyle={styles.listContent}\n      \u002F>\n    \u003C\u002FView>\n  );\n}\n\nconst styles = StyleSheet.create({\n  container: { flex: 1, backgroundColor: '#f5f5f5' },\n  banner: {\n    backgroundColor: '#FFA726',\n    padding: 12,\n    alignItems: 'center',\n  },\n  bannerText: { color: '#fff', fontWeight: '600' },\n  title: {\n    fontSize: 24,\n    fontWeight: 'bold',\n    padding: 16,\n  },\n  inputRow: {\n    flexDirection: 'row',\n    padding: 16,\n    gap: 8,\n  },\n  input: {\n    flex: 1,\n    backgroundColor: '#fff',\n    borderRadius: 8,\n    paddingHorizontal: 12,\n    paddingVertical: 10,\n    borderWidth: 1,\n    borderColor: '#ddd',\n  },\n  addButton: {\n    backgroundColor: '#2196F3',\n    width: 48,\n    height: 48,\n    borderRadius: 24,\n    alignItems: 'center',\n    justifyContent: 'center',\n  },\n  addButtonText: {\n    color: '#fff',\n    fontSize: 24,\n    fontWeight: 'bold',\n  },\n  listContent: { padding: 16, gap: 8 },\n  taskCard: {\n    backgroundColor: '#fff',\n    padding: 16,\n    borderRadius: 8,\n    borderWidth: 1,\n    borderColor: '#e0e0e0',\n  },\n  taskText: { fontSize: 16, marginBottom: 8 },\n  taskFooter: { flexDirection: 'row', alignItems: 'center', gap: 8 },\n  badge: {\n    fontSize: 12,\n    color: '#757575',\n  },\n  badgeSyncing: { color: '#2196F3' },\n  badgeSynced: { color: '#4CAF50' },\n  badgeError: { color: '#F44336' },\n  errorRow: { flexDirection: 'row', alignItems: 'center', gap: 8 },\n  retryButton: {\n    fontSize: 12,\n    color: '#2196F3',\n    fontWeight: '600',\n  },\n});\n","app\u002Findex.tsx",[3780,7525,7526,7568,7588,7606,7623,7640,7644,7657,7681,7707,7719,7723,7734,7738,7752,7768,7784,7795,7799,7804,7808,7814,7832,7841,7849,7864,7895,7903,7907,7911,7941,7945,7954,7969,7976,7988,7998,8010,8021,8033,8038,8063,8084,8093,8103,8108,8118,8126,8138,8151,8165,8181,8206,8221,8239,8269,8275,8292,8306,8311,8317,8323,8328,8334,8340,8346,8352,8358,8364,8370,8375,8381,8387,8393,8399,8405,8411,8416,8421,8426,8432,8456,8464,8475,8486,8497,8503,8527,8535,8546,8557,8567,8572,8580,8591,8600,8611,8616,8624,8634,8643,8653,8663,8674,8684,8695,8700,8708,8718,8729,8739,8748,8757,8767,8772,8780,8790,8799,8808,8813,8835,8843,8852,8861,8870,8879,8889,8894,8916,8944,8952,8961,8971,8976,8990,9005,9020,9046,9054,9063,9072,9081,9086],{"__ignoreMap":3978},[3982,7527,7528,7530,7532,7534,7536,7539,7541,7544,7546,7549,7551,7554,7556,7559,7561,7563,7566],{"class":3984,"line":3985},[3982,7529,5211],{"class":5210},[3982,7531,5444],{"class":3996},[3982,7533,5728],{"class":4003},[3982,7535,3783],{"class":3996},[3982,7537,7538],{"class":4003},"Text",[3982,7540,3783],{"class":3996},[3982,7542,7543],{"class":4003},"TextInput",[3982,7545,3783],{"class":3996},[3982,7547,7548],{"class":4003},"FlatList",[3982,7550,3783],{"class":3996},[3982,7552,7553],{"class":4003},"Pressable",[3982,7555,3783],{"class":3996},[3982,7557,7558],{"class":4003},"StyleSheet",[3982,7560,5455],{"class":3996},[3982,7562,5458],{"class":5210},[3982,7564,7565],{"class":4028}," 'react-native'",[3982,7567,4043],{"class":3996},[3982,7569,7570,7572,7574,7576,7578,7580,7582,7584,7586],{"class":3984,"line":4000},[3982,7571,5211],{"class":5210},[3982,7573,5444],{"class":3996},[3982,7575,5452],{"class":4003},[3982,7577,3783],{"class":3996},[3982,7579,5447],{"class":4003},[3982,7581,5455],{"class":3996},[3982,7583,5458],{"class":5210},[3982,7585,5461],{"class":4028},[3982,7587,4043],{"class":3996},[3982,7589,7590,7592,7594,7597,7599,7601,7604],{"class":3984,"line":4020},[3982,7591,5211],{"class":5210},[3982,7593,5444],{"class":3996},[3982,7595,7596],{"class":4003},"useStore",[3982,7598,5455],{"class":3996},[3982,7600,5458],{"class":5210},[3982,7602,7603],{"class":4028}," '..\u002Fstore\u002FuseStore'",[3982,7605,4043],{"class":3996},[3982,7607,7608,7610,7612,7614,7616,7618,7621],{"class":3984,"line":4046},[3982,7609,5211],{"class":5210},[3982,7611,5444],{"class":3996},[3982,7613,5091],{"class":4003},[3982,7615,5455],{"class":3996},[3982,7617,5458],{"class":5210},[3982,7619,7620],{"class":4028}," '..\u002Fhooks\u002FuseSyncWorker'",[3982,7622,4043],{"class":3996},[3982,7624,7625,7627,7629,7631,7633,7635,7638],{"class":3984,"line":4069},[3982,7626,5211],{"class":5210},[3982,7628,5444],{"class":3996},[3982,7630,5707],{"class":4003},[3982,7632,5455],{"class":3996},[3982,7634,5458],{"class":5210},[3982,7636,7637],{"class":4028}," '..\u002Fhooks\u002FuseNetworkStatus'",[3982,7639,4043],{"class":3996},[3982,7641,7642],{"class":3984,"line":4086},[3982,7643,4832],{"emptyLinePlaceholder":4831},[3982,7645,7646,7648,7650,7652,7655],{"class":3984,"line":4103},[3982,7647,5484],{"class":5210},[3982,7649,7483],{"class":5210},[3982,7651,5487],{"class":3988},[3982,7653,7654],{"class":5253}," HomeScreen",[3982,7656,5493],{"class":3996},[3982,7658,7659,7661,7663,7665,7667,7670,7672,7674,7676,7679],{"class":3984,"line":4119},[3982,7660,5498],{"class":3988},[3982,7662,5501],{"class":3996},[3982,7664,6479],{"class":5239},[3982,7666,3783],{"class":3996},[3982,7668,7669],{"class":5239},"setText",[3982,7671,5512],{"class":3996},[3982,7673,5452],{"class":5253},[3982,7675,5270],{"class":3996},[3982,7677,7678],{"class":4028},"''",[3982,7680,5375],{"class":3996},[3982,7682,7683,7685,7687,7690,7692,7695,7697,7700,7703,7705],{"class":3984,"line":4135},[3982,7684,5498],{"class":3988},[3982,7686,5444],{"class":3996},[3982,7688,7689],{"class":5239},"tasks",[3982,7691,3783],{"class":3996},[3982,7693,7694],{"class":5239},"addTask",[3982,7696,3783],{"class":3996},[3982,7698,7699],{"class":5239},"retrySync",[3982,7701,7702],{"class":3996}," } = ",[3982,7704,7596],{"class":5253},[3982,7706,5257],{"class":3996},[3982,7708,7709,7711,7713,7715,7717],{"class":3984,"line":4859},[3982,7710,5498],{"class":3988},[3982,7712,5670],{"class":5239},[3982,7714,5243],{"class":3996},[3982,7716,5707],{"class":5253},[3982,7718,5257],{"class":3996},[3982,7720,7721],{"class":3984,"line":4865},[3982,7722,4832],{"emptyLinePlaceholder":4831},[3982,7724,7725,7728,7731],{"class":3984,"line":4871},[3982,7726,7727],{"class":5253},"  useSyncWorker",[3982,7729,7730],{"class":3996},"(); ",[3982,7732,7733],{"class":4016},"\u002F\u002F Запускає фонову синхронізацію\n",[3982,7735,7736],{"class":3984,"line":4877},[3982,7737,4832],{"emptyLinePlaceholder":4831},[3982,7739,7740,7742,7745,7748,7750],{"class":3984,"line":4883},[3982,7741,5498],{"class":3988},[3982,7743,7744],{"class":5253}," handleAdd",[3982,7746,7747],{"class":3996}," = () ",[3982,7749,5536],{"class":3988},[3982,7751,5342],{"class":3996},[3982,7753,7754,7756,7758,7760,7762,7765],{"class":3984,"line":4888},[3982,7755,6324],{"class":5210},[3982,7757,3778],{"class":3996},[3982,7759,6479],{"class":4003},[3982,7761,3823],{"class":3996},[3982,7763,7764],{"class":5253},"trim",[3982,7766,7767],{"class":3996},"()) {\n",[3982,7769,7770,7773,7775,7777,7779,7781],{"class":3984,"line":4893},[3982,7771,7772],{"class":5253},"      addTask",[3982,7774,5270],{"class":3996},[3982,7776,6479],{"class":4003},[3982,7778,3823],{"class":3996},[3982,7780,7764],{"class":5253},[3982,7782,7783],{"class":3996},"());\n",[3982,7785,7786,7789,7791,7793],{"class":3984,"line":4899},[3982,7787,7788],{"class":5253},"      setText",[3982,7790,5270],{"class":3996},[3982,7792,7678],{"class":4028},[3982,7794,5375],{"class":3996},[3982,7796,7797],{"class":3984,"line":4905},[3982,7798,6492],{"class":3996},[3982,7800,7801],{"class":3984,"line":4911},[3982,7802,7803],{"class":3996},"  };\n",[3982,7805,7806],{"class":3984,"line":4916},[3982,7807,4832],{"emptyLinePlaceholder":4831},[3982,7809,7810,7812],{"class":3984,"line":4921},[3982,7811,5667],{"class":5210},[3982,7813,5720],{"class":3996},[3982,7815,7816,7818,7820,7823,7826,7829],{"class":3984,"line":4927},[3982,7817,5725],{"class":3996},[3982,7819,5728],{"class":4003},[3982,7821,7822],{"class":4003}," style",[3982,7824,7825],{"class":3996},"={styles.",[3982,7827,7828],{"class":4003},"container",[3982,7830,7831],{"class":3996},"}>\n",[3982,7833,7834,7836,7839],{"class":3984,"line":4933},[3982,7835,5814],{"class":3996},[3982,7837,7838],{"class":4016},"\u002F* Network banner *\u002F",[3982,7840,4852],{"class":3996},[3982,7842,7843,7845,7847],{"class":3984,"line":4938},[3982,7844,5736],{"class":3996},[3982,7846,5504],{"class":4003},[3982,7848,5741],{"class":3996},[3982,7850,7851,7853,7855,7857,7859,7862],{"class":3984,"line":4943},[3982,7852,5746],{"class":3996},[3982,7854,5728],{"class":4003},[3982,7856,7822],{"class":4003},[3982,7858,7825],{"class":3996},[3982,7860,7861],{"class":4003},"banner",[3982,7863,7831],{"class":3996},[3982,7865,7866,7869,7871,7873,7875,7878,7881,7884,7886,7888,7891,7893],{"class":3984,"line":4949},[3982,7867,7868],{"class":3996},"          \u003C",[3982,7870,7538],{"class":4003},[3982,7872,7822],{"class":4003},[3982,7874,7825],{"class":3996},[3982,7876,7877],{"class":4003},"bannerText",[3982,7879,7880],{"class":3996},"}>📡 ",[3982,7882,7883],{"class":4003},"Офлайн",[3982,7885,5768],{"class":3996},[3982,7887,5771],{"class":4003},[3982,7889,7890],{"class":3996},"\u003C\u002F",[3982,7892,7538],{"class":4003},[3982,7894,5731],{"class":3996},[3982,7896,7897,7899,7901],{"class":3984,"line":4954},[3982,7898,5800],{"class":3996},[3982,7900,5728],{"class":4003},[3982,7902,5731],{"class":3996},[3982,7904,7905],{"class":3984,"line":4960},[3982,7906,5809],{"class":3996},[3982,7908,7909],{"class":3984,"line":4966},[3982,7910,4832],{"emptyLinePlaceholder":4831},[3982,7912,7913,7916,7918,7920,7922,7925,7928,7930,7932,7935,7937,7939],{"class":3984,"line":4972},[3982,7914,7915],{"class":3996},"      \u003C",[3982,7917,7538],{"class":4003},[3982,7919,7822],{"class":4003},[3982,7921,7825],{"class":3996},[3982,7923,7924],{"class":4003},"title",[3982,7926,7927],{"class":3996},"}>",[3982,7929,7883],{"class":4003},[3982,7931,5768],{"class":3996},[3982,7933,7934],{"class":4003},"чеклист",[3982,7936,7890],{"class":3996},[3982,7938,7538],{"class":4003},[3982,7940,5731],{"class":3996},[3982,7942,7943],{"class":3984,"line":4978},[3982,7944,4832],{"emptyLinePlaceholder":4831},[3982,7946,7947,7949,7952],{"class":3984,"line":4983},[3982,7948,5814],{"class":3996},[3982,7950,7951],{"class":4016},"\u002F* Input *\u002F",[3982,7953,4852],{"class":3996},[3982,7955,7956,7958,7960,7962,7964,7967],{"class":3984,"line":4989},[3982,7957,7915],{"class":3996},[3982,7959,5728],{"class":4003},[3982,7961,7822],{"class":4003},[3982,7963,7825],{"class":3996},[3982,7965,7966],{"class":4003},"inputRow",[3982,7968,7831],{"class":3996},[3982,7970,7971,7973],{"class":3984,"line":4995},[3982,7972,5746],{"class":3996},[3982,7974,7975],{"class":4003},"TextInput\n",[3982,7977,7978,7981,7983,7986],{"class":3984,"line":5001},[3982,7979,7980],{"class":4003},"          style",[3982,7982,7825],{"class":3996},[3982,7984,7985],{"class":4003},"input",[3982,7987,4852],{"class":3996},[3982,7989,7990,7993,7995],{"class":3984,"line":5007},[3982,7991,7992],{"class":4003},"          placeholder",[3982,7994,5755],{"class":3996},[3982,7996,7997],{"class":4028},"\"Нове завдання...\"\n",[3982,7999,8000,8003,8006,8008],{"class":3984,"line":5013},[3982,8001,8002],{"class":4003},"          value",[3982,8004,8005],{"class":3996},"={",[3982,8007,6479],{"class":4003},[3982,8009,4852],{"class":3996},[3982,8011,8012,8015,8017,8019],{"class":3984,"line":5018},[3982,8013,8014],{"class":4003},"          onChangeText",[3982,8016,8005],{"class":3996},[3982,8018,7669],{"class":4003},[3982,8020,4852],{"class":3996},[3982,8022,8023,8026,8028,8031],{"class":3984,"line":5024},[3982,8024,8025],{"class":4003},"          onSubmitEditing",[3982,8027,8005],{"class":3996},[3982,8029,8030],{"class":4003},"handleAdd",[3982,8032,4852],{"class":3996},[3982,8034,8035],{"class":3984,"line":5030},[3982,8036,8037],{"class":3996},"        \u002F>\n",[3982,8039,8040,8042,8044,8046,8048,8051,8054,8057,8059,8061],{"class":3984,"line":5035},[3982,8041,5746],{"class":3996},[3982,8043,7553],{"class":4003},[3982,8045,7822],{"class":4003},[3982,8047,7825],{"class":3996},[3982,8049,8050],{"class":4003},"addButton",[3982,8052,8053],{"class":3996},"} ",[3982,8055,8056],{"class":4003},"onPress",[3982,8058,8005],{"class":3996},[3982,8060,8030],{"class":4003},[3982,8062,7831],{"class":3996},[3982,8064,8066,8068,8070,8072,8074,8077,8080,8082],{"class":3984,"line":8065},42,[3982,8067,7868],{"class":3996},[3982,8069,7538],{"class":4003},[3982,8071,7822],{"class":4003},[3982,8073,7825],{"class":3996},[3982,8075,8076],{"class":4003},"addButtonText",[3982,8078,8079],{"class":3996},"}>+\u003C\u002F",[3982,8081,7538],{"class":3992},[3982,8083,5731],{"class":3996},[3982,8085,8087,8089,8091],{"class":3984,"line":8086},43,[3982,8088,5800],{"class":3996},[3982,8090,7553],{"class":4003},[3982,8092,5731],{"class":3996},[3982,8094,8096,8099,8101],{"class":3984,"line":8095},44,[3982,8097,8098],{"class":3996},"      \u003C\u002F",[3982,8100,5728],{"class":4003},[3982,8102,5731],{"class":3996},[3982,8104,8106],{"class":3984,"line":8105},45,[3982,8107,4832],{"emptyLinePlaceholder":4831},[3982,8109,8111,8113,8116],{"class":3984,"line":8110},46,[3982,8112,5814],{"class":3996},[3982,8114,8115],{"class":4016},"\u002F* List *\u002F",[3982,8117,4852],{"class":3996},[3982,8119,8121,8123],{"class":3984,"line":8120},47,[3982,8122,7915],{"class":3996},[3982,8124,8125],{"class":4003},"FlatList\n",[3982,8127,8129,8132,8134,8136],{"class":3984,"line":8128},48,[3982,8130,8131],{"class":4003},"        data",[3982,8133,8005],{"class":3996},[3982,8135,7689],{"class":4003},[3982,8137,4852],{"class":3996},[3982,8139,8141,8144,8147,8149],{"class":3984,"line":8140},49,[3982,8142,8143],{"class":4003},"        keyExtractor",[3982,8145,8146],{"class":3996},"={(item) => item.",[3982,8148,5166],{"class":4003},[3982,8150,4852],{"class":3996},[3982,8152,8154,8157,8160,8162],{"class":3984,"line":8153},50,[3982,8155,8156],{"class":4003},"        renderItem",[3982,8158,8159],{"class":3996},"={({ ",[3982,8161,6074],{"class":4003},[3982,8163,8164],{"class":3996}," }) => (\n",[3982,8166,8168,8171,8174,8176,8179],{"class":3984,"line":8167},51,[3982,8169,8170],{"class":3996},"          \u003CView ",[3982,8172,8173],{"class":4003},"style",[3982,8175,7825],{"class":3996},[3982,8177,8178],{"class":4003},"taskCard",[3982,8180,7831],{"class":3996},[3982,8182,8184,8187,8189,8191,8194,8197,8199,8202,8204],{"class":3984,"line":8183},52,[3982,8185,8186],{"class":3996},"            \u003CText ",[3982,8188,8173],{"class":4003},[3982,8190,7825],{"class":3996},[3982,8192,8193],{"class":4003},"taskText",[3982,8195,8196],{"class":3996},"}>{item.",[3982,8198,6479],{"class":4003},[3982,8200,8201],{"class":3996},"}\u003C\u002F",[3982,8203,7538],{"class":4003},[3982,8205,5731],{"class":3996},[3982,8207,8209,8212,8214,8216,8219],{"class":3984,"line":8208},53,[3982,8210,8211],{"class":3996},"            \u003CView ",[3982,8213,8173],{"class":4003},[3982,8215,7825],{"class":3996},[3982,8217,8218],{"class":4003},"taskFooter",[3982,8220,7831],{"class":3996},[3982,8222,8224,8227,8229,8231,8233,8235,8237],{"class":3984,"line":8223},54,[3982,8225,8226],{"class":3996},"              {",[3982,8228,6074],{"class":4003},[3982,8230,3823],{"class":3996},[3982,8232,3818],{"class":4003},[3982,8234,6270],{"class":3996},[3982,8236,4265],{"class":4028},[3982,8238,5741],{"class":3996},[3982,8240,8242,8245,8247,8249,8251,8254,8257,8260,8263,8265,8267],{"class":3984,"line":8241},55,[3982,8243,8244],{"class":3996},"                \u003C",[3982,8246,7538],{"class":4003},[3982,8248,7822],{"class":4003},[3982,8250,7825],{"class":3996},[3982,8252,8253],{"class":4003},"badge",[3982,8255,8256],{"class":3996},"}>⏳ ",[3982,8258,8259],{"class":4003},"Не",[3982,8261,8262],{"class":4003}," синхронізовано",[3982,8264,7890],{"class":3996},[3982,8266,7538],{"class":4003},[3982,8268,5731],{"class":3996},[3982,8270,8272],{"class":3984,"line":8271},56,[3982,8273,8274],{"class":3996},"              )}\n",[3982,8276,8278,8280,8282,8284,8286,8288,8290],{"class":3984,"line":8277},57,[3982,8279,8226],{"class":3996},[3982,8281,6074],{"class":4003},[3982,8283,3823],{"class":3996},[3982,8285,3818],{"class":4003},[3982,8287,6270],{"class":3996},[3982,8289,4275],{"class":4028},[3982,8291,5741],{"class":3996},[3982,8293,8295,8297,8299,8301,8303],{"class":3984,"line":8294},58,[3982,8296,8244],{"class":3996},[3982,8298,7538],{"class":4003},[3982,8300,7822],{"class":4003},[3982,8302,8005],{"class":3996},[3982,8304,8305],{"class":4003},"[styles.badge, styles.badgeSyncing]}>🔄 Відправляється...\u003C\u002FText>\n",[3982,8307,8309],{"class":3984,"line":8308},59,[3982,8310,8274],{"class":4003},[3982,8312,8314],{"class":3984,"line":8313},60,[3982,8315,8316],{"class":4003},"              {item.syncStatus === 'synced' && (\n",[3982,8318,8320],{"class":3984,"line":8319},61,[3982,8321,8322],{"class":4003},"                \u003CText style={[styles.badge, styles.badgeSynced]}>✅ Синхронізовано\u003C\u002FText>\n",[3982,8324,8326],{"class":3984,"line":8325},62,[3982,8327,8274],{"class":4003},[3982,8329,8331],{"class":3984,"line":8330},63,[3982,8332,8333],{"class":4003},"              {item.syncStatus === 'error' && (\n",[3982,8335,8337],{"class":3984,"line":8336},64,[3982,8338,8339],{"class":4003},"                \u003CView style={styles.errorRow}>\n",[3982,8341,8343],{"class":3984,"line":8342},65,[3982,8344,8345],{"class":4003},"                  \u003CText style={[styles.badge, styles.badgeError]}>❌ Помилка\u003C\u002FText>\n",[3982,8347,8349],{"class":3984,"line":8348},66,[3982,8350,8351],{"class":4003},"                  \u003CPressable onPress={() => retrySync(item.id)}>\n",[3982,8353,8355],{"class":3984,"line":8354},67,[3982,8356,8357],{"class":4003},"                    \u003CText style={styles.retryButton}>Повторити\u003C\u002FText>\n",[3982,8359,8361],{"class":3984,"line":8360},68,[3982,8362,8363],{"class":4003},"                  \u003C\u002FPressable>\n",[3982,8365,8367],{"class":3984,"line":8366},69,[3982,8368,8369],{"class":4003},"                \u003C\u002FView>\n",[3982,8371,8373],{"class":3984,"line":8372},70,[3982,8374,8274],{"class":4003},[3982,8376,8378],{"class":3984,"line":8377},71,[3982,8379,8380],{"class":4003},"            \u003C\u002FView>\n",[3982,8382,8384],{"class":3984,"line":8383},72,[3982,8385,8386],{"class":4003},"          \u003C\u002FView>\n",[3982,8388,8390],{"class":3984,"line":8389},73,[3982,8391,8392],{"class":4003},"        )}\n",[3982,8394,8396],{"class":3984,"line":8395},74,[3982,8397,8398],{"class":4003},"        contentContainerStyle={styles.listContent}\n",[3982,8400,8402],{"class":3984,"line":8401},75,[3982,8403,8404],{"class":4003},"      \u002F>\n",[3982,8406,8408],{"class":3984,"line":8407},76,[3982,8409,8410],{"class":4003},"    \u003C\u002FView>\n",[3982,8412,8414],{"class":3984,"line":8413},77,[3982,8415,5833],{"class":4003},[3982,8417,8419],{"class":3984,"line":8418},78,[3982,8420,4852],{"class":4003},[3982,8422,8424],{"class":3984,"line":8423},79,[3982,8425,4832],{"emptyLinePlaceholder":4831},[3982,8427,8429],{"class":3984,"line":8428},80,[3982,8430,8431],{"class":4003},"const styles = StyleSheet.create({\n",[3982,8433,8435,8438,8440,8443,8446,8448,8451,8454],{"class":3984,"line":8434},81,[3982,8436,8437],{"class":4003},"  container:",[3982,8439,5444],{"class":3996},[3982,8441,8442],{"class":4003},"flex:",[3982,8444,8445],{"class":6014}," 1",[3982,8447,3783],{"class":3996},[3982,8449,8450],{"class":4003},"backgroundColor:",[3982,8452,8453],{"class":4028}," '#f5f5f5'",[3982,8455,6978],{"class":3996},[3982,8457,8459,8462],{"class":3984,"line":8458},82,[3982,8460,8461],{"class":4003},"  banner:",[3982,8463,5342],{"class":3996},[3982,8465,8467,8470,8473],{"class":3984,"line":8466},83,[3982,8468,8469],{"class":4003},"    backgroundColor:",[3982,8471,8472],{"class":4028}," '#FFA726'",[3982,8474,6287],{"class":3996},[3982,8476,8478,8481,8484],{"class":3984,"line":8477},84,[3982,8479,8480],{"class":4003},"    padding:",[3982,8482,8483],{"class":6014}," 12",[3982,8485,6287],{"class":3996},[3982,8487,8489,8492,8495],{"class":3984,"line":8488},85,[3982,8490,8491],{"class":4003},"    alignItems:",[3982,8493,8494],{"class":4028}," 'center'",[3982,8496,6287],{"class":3996},[3982,8498,8500],{"class":3984,"line":8499},86,[3982,8501,8502],{"class":3996},"  },\n",[3982,8504,8506,8509,8511,8514,8517,8519,8522,8525],{"class":3984,"line":8505},87,[3982,8507,8508],{"class":4003},"  bannerText:",[3982,8510,5444],{"class":3996},[3982,8512,8513],{"class":4003},"color:",[3982,8515,8516],{"class":4028}," '#fff'",[3982,8518,3783],{"class":3996},[3982,8520,8521],{"class":4003},"fontWeight:",[3982,8523,8524],{"class":4028}," '600'",[3982,8526,6978],{"class":3996},[3982,8528,8530,8533],{"class":3984,"line":8529},88,[3982,8531,8532],{"class":4003},"  title:",[3982,8534,5342],{"class":3996},[3982,8536,8538,8541,8544],{"class":3984,"line":8537},89,[3982,8539,8540],{"class":4003},"    fontSize:",[3982,8542,8543],{"class":6014}," 24",[3982,8545,6287],{"class":3996},[3982,8547,8549,8552,8555],{"class":3984,"line":8548},90,[3982,8550,8551],{"class":4003},"    fontWeight:",[3982,8553,8554],{"class":4028}," 'bold'",[3982,8556,6287],{"class":3996},[3982,8558,8560,8562,8565],{"class":3984,"line":8559},91,[3982,8561,8480],{"class":4003},[3982,8563,8564],{"class":6014}," 16",[3982,8566,6287],{"class":3996},[3982,8568,8570],{"class":3984,"line":8569},92,[3982,8571,8502],{"class":3996},[3982,8573,8575,8578],{"class":3984,"line":8574},93,[3982,8576,8577],{"class":4003},"  inputRow:",[3982,8579,5342],{"class":3996},[3982,8581,8583,8586,8589],{"class":3984,"line":8582},94,[3982,8584,8585],{"class":4003},"    flexDirection:",[3982,8587,8588],{"class":4028}," 'row'",[3982,8590,6287],{"class":3996},[3982,8592,8594,8596,8598],{"class":3984,"line":8593},95,[3982,8595,8480],{"class":4003},[3982,8597,8564],{"class":6014},[3982,8599,6287],{"class":3996},[3982,8601,8603,8606,8609],{"class":3984,"line":8602},96,[3982,8604,8605],{"class":4003},"    gap:",[3982,8607,8608],{"class":6014}," 8",[3982,8610,6287],{"class":3996},[3982,8612,8614],{"class":3984,"line":8613},97,[3982,8615,8502],{"class":3996},[3982,8617,8619,8622],{"class":3984,"line":8618},98,[3982,8620,8621],{"class":4003},"  input:",[3982,8623,5342],{"class":3996},[3982,8625,8627,8630,8632],{"class":3984,"line":8626},99,[3982,8628,8629],{"class":4003},"    flex:",[3982,8631,8445],{"class":6014},[3982,8633,6287],{"class":3996},[3982,8635,8637,8639,8641],{"class":3984,"line":8636},100,[3982,8638,8469],{"class":4003},[3982,8640,8516],{"class":4028},[3982,8642,6287],{"class":3996},[3982,8644,8646,8649,8651],{"class":3984,"line":8645},101,[3982,8647,8648],{"class":4003},"    borderRadius:",[3982,8650,8608],{"class":6014},[3982,8652,6287],{"class":3996},[3982,8654,8656,8659,8661],{"class":3984,"line":8655},102,[3982,8657,8658],{"class":4003},"    paddingHorizontal:",[3982,8660,8483],{"class":6014},[3982,8662,6287],{"class":3996},[3982,8664,8666,8669,8672],{"class":3984,"line":8665},103,[3982,8667,8668],{"class":4003},"    paddingVertical:",[3982,8670,8671],{"class":6014}," 10",[3982,8673,6287],{"class":3996},[3982,8675,8677,8680,8682],{"class":3984,"line":8676},104,[3982,8678,8679],{"class":4003},"    borderWidth:",[3982,8681,8445],{"class":6014},[3982,8683,6287],{"class":3996},[3982,8685,8687,8690,8693],{"class":3984,"line":8686},105,[3982,8688,8689],{"class":4003},"    borderColor:",[3982,8691,8692],{"class":4028}," '#ddd'",[3982,8694,6287],{"class":3996},[3982,8696,8698],{"class":3984,"line":8697},106,[3982,8699,8502],{"class":3996},[3982,8701,8703,8706],{"class":3984,"line":8702},107,[3982,8704,8705],{"class":4003},"  addButton:",[3982,8707,5342],{"class":3996},[3982,8709,8711,8713,8716],{"class":3984,"line":8710},108,[3982,8712,8469],{"class":4003},[3982,8714,8715],{"class":4028}," '#2196F3'",[3982,8717,6287],{"class":3996},[3982,8719,8721,8724,8727],{"class":3984,"line":8720},109,[3982,8722,8723],{"class":4003},"    width:",[3982,8725,8726],{"class":6014}," 48",[3982,8728,6287],{"class":3996},[3982,8730,8732,8735,8737],{"class":3984,"line":8731},110,[3982,8733,8734],{"class":4003},"    height:",[3982,8736,8726],{"class":6014},[3982,8738,6287],{"class":3996},[3982,8740,8742,8744,8746],{"class":3984,"line":8741},111,[3982,8743,8648],{"class":4003},[3982,8745,8543],{"class":6014},[3982,8747,6287],{"class":3996},[3982,8749,8751,8753,8755],{"class":3984,"line":8750},112,[3982,8752,8491],{"class":4003},[3982,8754,8494],{"class":4028},[3982,8756,6287],{"class":3996},[3982,8758,8760,8763,8765],{"class":3984,"line":8759},113,[3982,8761,8762],{"class":4003},"    justifyContent:",[3982,8764,8494],{"class":4028},[3982,8766,6287],{"class":3996},[3982,8768,8770],{"class":3984,"line":8769},114,[3982,8771,8502],{"class":3996},[3982,8773,8775,8778],{"class":3984,"line":8774},115,[3982,8776,8777],{"class":4003},"  addButtonText:",[3982,8779,5342],{"class":3996},[3982,8781,8783,8786,8788],{"class":3984,"line":8782},116,[3982,8784,8785],{"class":4003},"    color:",[3982,8787,8516],{"class":4028},[3982,8789,6287],{"class":3996},[3982,8791,8793,8795,8797],{"class":3984,"line":8792},117,[3982,8794,8540],{"class":4003},[3982,8796,8543],{"class":6014},[3982,8798,6287],{"class":3996},[3982,8800,8802,8804,8806],{"class":3984,"line":8801},118,[3982,8803,8551],{"class":4003},[3982,8805,8554],{"class":4028},[3982,8807,6287],{"class":3996},[3982,8809,8811],{"class":3984,"line":8810},119,[3982,8812,8502],{"class":3996},[3982,8814,8816,8819,8821,8824,8826,8828,8831,8833],{"class":3984,"line":8815},120,[3982,8817,8818],{"class":4003},"  listContent:",[3982,8820,5444],{"class":3996},[3982,8822,8823],{"class":4003},"padding:",[3982,8825,8564],{"class":6014},[3982,8827,3783],{"class":3996},[3982,8829,8830],{"class":4003},"gap:",[3982,8832,8608],{"class":6014},[3982,8834,6978],{"class":3996},[3982,8836,8838,8841],{"class":3984,"line":8837},121,[3982,8839,8840],{"class":4003},"  taskCard:",[3982,8842,5342],{"class":3996},[3982,8844,8846,8848,8850],{"class":3984,"line":8845},122,[3982,8847,8469],{"class":4003},[3982,8849,8516],{"class":4028},[3982,8851,6287],{"class":3996},[3982,8853,8855,8857,8859],{"class":3984,"line":8854},123,[3982,8856,8480],{"class":4003},[3982,8858,8564],{"class":6014},[3982,8860,6287],{"class":3996},[3982,8862,8864,8866,8868],{"class":3984,"line":8863},124,[3982,8865,8648],{"class":4003},[3982,8867,8608],{"class":6014},[3982,8869,6287],{"class":3996},[3982,8871,8873,8875,8877],{"class":3984,"line":8872},125,[3982,8874,8679],{"class":4003},[3982,8876,8445],{"class":6014},[3982,8878,6287],{"class":3996},[3982,8880,8882,8884,8887],{"class":3984,"line":8881},126,[3982,8883,8689],{"class":4003},[3982,8885,8886],{"class":4028}," '#e0e0e0'",[3982,8888,6287],{"class":3996},[3982,8890,8892],{"class":3984,"line":8891},127,[3982,8893,8502],{"class":3996},[3982,8895,8897,8900,8902,8905,8907,8909,8912,8914],{"class":3984,"line":8896},128,[3982,8898,8899],{"class":4003},"  taskText:",[3982,8901,5444],{"class":3996},[3982,8903,8904],{"class":4003},"fontSize:",[3982,8906,8564],{"class":6014},[3982,8908,3783],{"class":3996},[3982,8910,8911],{"class":4003},"marginBottom:",[3982,8913,8608],{"class":6014},[3982,8915,6978],{"class":3996},[3982,8917,8919,8922,8924,8927,8929,8931,8934,8936,8938,8940,8942],{"class":3984,"line":8918},129,[3982,8920,8921],{"class":4003},"  taskFooter:",[3982,8923,5444],{"class":3996},[3982,8925,8926],{"class":4003},"flexDirection:",[3982,8928,8588],{"class":4028},[3982,8930,3783],{"class":3996},[3982,8932,8933],{"class":4003},"alignItems:",[3982,8935,8494],{"class":4028},[3982,8937,3783],{"class":3996},[3982,8939,8830],{"class":4003},[3982,8941,8608],{"class":6014},[3982,8943,6978],{"class":3996},[3982,8945,8947,8950],{"class":3984,"line":8946},130,[3982,8948,8949],{"class":4003},"  badge:",[3982,8951,5342],{"class":3996},[3982,8953,8955,8957,8959],{"class":3984,"line":8954},131,[3982,8956,8540],{"class":4003},[3982,8958,8483],{"class":6014},[3982,8960,6287],{"class":3996},[3982,8962,8964,8966,8969],{"class":3984,"line":8963},132,[3982,8965,8785],{"class":4003},[3982,8967,8968],{"class":4028}," '#757575'",[3982,8970,6287],{"class":3996},[3982,8972,8974],{"class":3984,"line":8973},133,[3982,8975,8502],{"class":3996},[3982,8977,8979,8982,8984,8986,8988],{"class":3984,"line":8978},134,[3982,8980,8981],{"class":4003},"  badgeSyncing:",[3982,8983,5444],{"class":3996},[3982,8985,8513],{"class":4003},[3982,8987,8715],{"class":4028},[3982,8989,6978],{"class":3996},[3982,8991,8993,8996,8998,9000,9003],{"class":3984,"line":8992},135,[3982,8994,8995],{"class":4003},"  badgeSynced:",[3982,8997,5444],{"class":3996},[3982,8999,8513],{"class":4003},[3982,9001,9002],{"class":4028}," '#4CAF50'",[3982,9004,6978],{"class":3996},[3982,9006,9008,9011,9013,9015,9018],{"class":3984,"line":9007},136,[3982,9009,9010],{"class":4003},"  badgeError:",[3982,9012,5444],{"class":3996},[3982,9014,8513],{"class":4003},[3982,9016,9017],{"class":4028}," '#F44336'",[3982,9019,6978],{"class":3996},[3982,9021,9023,9026,9028,9030,9032,9034,9036,9038,9040,9042,9044],{"class":3984,"line":9022},137,[3982,9024,9025],{"class":4003},"  errorRow:",[3982,9027,5444],{"class":3996},[3982,9029,8926],{"class":4003},[3982,9031,8588],{"class":4028},[3982,9033,3783],{"class":3996},[3982,9035,8933],{"class":4003},[3982,9037,8494],{"class":4028},[3982,9039,3783],{"class":3996},[3982,9041,8830],{"class":4003},[3982,9043,8608],{"class":6014},[3982,9045,6978],{"class":3996},[3982,9047,9049,9052],{"class":3984,"line":9048},138,[3982,9050,9051],{"class":4003},"  retryButton:",[3982,9053,5342],{"class":3996},[3982,9055,9057,9059,9061],{"class":3984,"line":9056},139,[3982,9058,8540],{"class":4003},[3982,9060,8483],{"class":6014},[3982,9062,6287],{"class":3996},[3982,9064,9066,9068,9070],{"class":3984,"line":9065},140,[3982,9067,8785],{"class":4003},[3982,9069,8715],{"class":4028},[3982,9071,6287],{"class":3996},[3982,9073,9075,9077,9079],{"class":3984,"line":9074},141,[3982,9076,8551],{"class":4003},[3982,9078,8524],{"class":4028},[3982,9080,6287],{"class":3996},[3982,9082,9084],{"class":3984,"line":9083},142,[3982,9085,8502],{"class":3996},[3982,9087,9089],{"class":3984,"line":9088},143,[3982,9090,5422],{"class":3996},[3973,9092,9096],{"className":9093,"code":9094,"filename":9095,"language":6479,"meta":3978},[7444],"store\u002F\n└── useStore.ts\n","store",[3780,9097,9094],{"__ignoreMap":3978},[3973,9099,9102],{"className":3975,"code":9100,"filename":9101,"language":3977,"meta":3978,"style":3978},"import { create } from 'zustand';\nimport { MMKV } from 'react-native-mmkv';\n\nconst storage = new MMKV();\n\nexport type SyncStatus = 'pending' | 'syncing' | 'synced' | 'error';\n\nexport type Task = {\n  id: string;\n  text: string;\n  syncStatus: SyncStatus;\n  syncError?: string;\n  createdAt: number;\n  retryCount: number;\n};\n\ntype Store = {\n  tasks: Task[];\n  addTask: (text: string) => void;\n  updateTaskStatus: (id: string, status: SyncStatus, serverId?: string, error?: string) => void;\n  retrySync: (id: string) => void;\n  loadTasks: () => void;\n};\n\nexport const useStore = create\u003CStore>((set, get) => ({\n  tasks: [],\n\n  loadTasks: () => {\n    const json = storage.getString('tasks');\n    if (json) {\n      const tasks = JSON.parse(json) as Task[];\n      set({ tasks });\n    }\n  },\n\n  addTask: (text: string) => {\n    const newTask: Task = {\n      id: `local-${Date.now()}`,\n      text,\n      syncStatus: 'pending',\n      createdAt: Date.now(),\n      retryCount: 0,\n    };\n\n    const tasks = [...get().tasks, newTask];\n    set({ tasks });\n    storage.set('tasks', JSON.stringify(tasks));\n  },\n\n  updateTaskStatus: (id, status, serverId, error) => {\n    const tasks = get().tasks.map((task) =>\n      task.id === id\n        ? { ...task, syncStatus: status, syncError: error, id: serverId || task.id }\n        : task\n    );\n    set({ tasks });\n    storage.set('tasks', JSON.stringify(tasks));\n  },\n\n  retrySync: (id) => {\n    const tasks = get().tasks.map((task) =>\n      task.id === id\n        ? { ...task, syncStatus: 'pending' as SyncStatus, retryCount: 0 }\n        : task\n    );\n    set({ tasks });\n    storage.set('tasks', JSON.stringify(tasks));\n  },\n}));\n","store\u002FuseStore.ts",[3780,9103,9104,9122,9140,9144,9161,9165,9192,9196,9207,9217,9228,9240,9251,9261,9271,9275,9279,9288,9301,9325,9371,9392,9406,9410,9414,9452,9460,9464,9477,9501,9511,9542,9554,9558,9562,9566,9586,9599,9626,9633,9643,9657,9666,9671,9675,9698,9709,9736,9740,9744,9772,9802,9816,9856,9864,9869,9879,9905,9909,9913,9929,9955,9967,9993,9999,10003,10013,10039,10043],{"__ignoreMap":3978},[3982,9105,9106,9108,9110,9113,9115,9117,9120],{"class":3984,"line":3985},[3982,9107,5211],{"class":5210},[3982,9109,5444],{"class":3996},[3982,9111,9112],{"class":4003},"create",[3982,9114,5455],{"class":3996},[3982,9116,5458],{"class":5210},[3982,9118,9119],{"class":4028}," 'zustand'",[3982,9121,4043],{"class":3996},[3982,9123,9124,9126,9128,9131,9133,9135,9138],{"class":3984,"line":4000},[3982,9125,5211],{"class":5210},[3982,9127,5444],{"class":3996},[3982,9129,9130],{"class":4003},"MMKV",[3982,9132,5455],{"class":3996},[3982,9134,5458],{"class":5210},[3982,9136,9137],{"class":4028}," 'react-native-mmkv'",[3982,9139,4043],{"class":3996},[3982,9141,9142],{"class":3984,"line":4020},[3982,9143,4832],{"emptyLinePlaceholder":4831},[3982,9145,9146,9148,9151,9153,9156,9159],{"class":3984,"line":4046},[3982,9147,5236],{"class":3988},[3982,9149,9150],{"class":5239}," storage",[3982,9152,5243],{"class":3996},[3982,9154,9155],{"class":3988},"new",[3982,9157,9158],{"class":5253}," MMKV",[3982,9160,5257],{"class":3996},[3982,9162,9163],{"class":3984,"line":4069},[3982,9164,4832],{"emptyLinePlaceholder":4831},[3982,9166,9167,9169,9172,9174,9176,9178,9180,9182,9184,9186,9188,9190],{"class":3984,"line":4086},[3982,9168,5484],{"class":5210},[3982,9170,9171],{"class":3988}," type",[3982,9173,4254],{"class":3992},[3982,9175,5243],{"class":3996},[3982,9177,4265],{"class":4028},[3982,9179,4032],{"class":3996},[3982,9181,4275],{"class":4028},[3982,9183,4032],{"class":3996},[3982,9185,4285],{"class":4028},[3982,9187,4032],{"class":3996},[3982,9189,4295],{"class":4028},[3982,9191,4043],{"class":3996},[3982,9193,9194],{"class":3984,"line":4103},[3982,9195,4832],{"emptyLinePlaceholder":4831},[3982,9197,9198,9200,9202,9205],{"class":3984,"line":4119},[3982,9199,5484],{"class":5210},[3982,9201,9171],{"class":3988},[3982,9203,9204],{"class":3992}," Task",[3982,9206,3997],{"class":3996},[3982,9208,9209,9211,9213,9215],{"class":3984,"line":4135},[3982,9210,4004],{"class":4003},[3982,9212,4007],{"class":3996},[3982,9214,4010],{"class":3992},[3982,9216,4043],{"class":3996},[3982,9218,9219,9222,9224,9226],{"class":3984,"line":4859},[3982,9220,9221],{"class":4003},"  text",[3982,9223,4007],{"class":3996},[3982,9225,4010],{"class":3992},[3982,9227,4043],{"class":3996},[3982,9229,9230,9233,9235,9238],{"class":3984,"line":4865},[3982,9231,9232],{"class":4003},"  syncStatus",[3982,9234,4007],{"class":3996},[3982,9236,9237],{"class":3992},"SyncStatus",[3982,9239,4043],{"class":3996},[3982,9241,9242,9245,9247,9249],{"class":3984,"line":4871},[3982,9243,9244],{"class":4003},"  syncError",[3982,9246,4125],{"class":3996},[3982,9248,4010],{"class":3992},[3982,9250,4043],{"class":3996},[3982,9252,9253,9255,9257,9259],{"class":3984,"line":4877},[3982,9254,4089],{"class":4003},[3982,9256,4007],{"class":3996},[3982,9258,4094],{"class":3992},[3982,9260,4043],{"class":3996},[3982,9262,9263,9265,9267,9269],{"class":3984,"line":4883},[3982,9264,4106],{"class":4003},[3982,9266,4007],{"class":3996},[3982,9268,4094],{"class":3992},[3982,9270,4043],{"class":3996},[3982,9272,9273],{"class":3984,"line":4888},[3982,9274,4138],{"class":3996},[3982,9276,9277],{"class":3984,"line":4893},[3982,9278,4832],{"emptyLinePlaceholder":4831},[3982,9280,9281,9283,9286],{"class":3984,"line":4899},[3982,9282,3989],{"class":3988},[3982,9284,9285],{"class":3992}," Store",[3982,9287,3997],{"class":3996},[3982,9289,9290,9293,9295,9298],{"class":3984,"line":4905},[3982,9291,9292],{"class":4003},"  tasks",[3982,9294,4007],{"class":3996},[3982,9296,9297],{"class":3992},"Task",[3982,9299,9300],{"class":3996},"[];\n",[3982,9302,9303,9306,9309,9311,9313,9315,9318,9320,9323],{"class":3984,"line":4911},[3982,9304,9305],{"class":5253},"  addTask",[3982,9307,9308],{"class":3996},": (",[3982,9310,6479],{"class":4003},[3982,9312,4007],{"class":3996},[3982,9314,4010],{"class":3992},[3982,9316,9317],{"class":3996},") ",[3982,9319,5536],{"class":3988},[3982,9321,9322],{"class":3992}," void",[3982,9324,4043],{"class":3996},[3982,9326,9327,9330,9332,9334,9336,9338,9340,9343,9345,9347,9349,9351,9353,9355,9357,9359,9361,9363,9365,9367,9369],{"class":3984,"line":4916},[3982,9328,9329],{"class":5253},"  updateTaskStatus",[3982,9331,9308],{"class":3996},[3982,9333,5166],{"class":4003},[3982,9335,4007],{"class":3996},[3982,9337,4010],{"class":3992},[3982,9339,3783],{"class":3996},[3982,9341,9342],{"class":4003},"status",[3982,9344,4007],{"class":3996},[3982,9346,9237],{"class":3992},[3982,9348,3783],{"class":3996},[3982,9350,4182],{"class":4003},[3982,9352,4125],{"class":3996},[3982,9354,4010],{"class":3992},[3982,9356,3783],{"class":3996},[3982,9358,3789],{"class":4003},[3982,9360,4125],{"class":3996},[3982,9362,4010],{"class":3992},[3982,9364,9317],{"class":3996},[3982,9366,5536],{"class":3988},[3982,9368,9322],{"class":3992},[3982,9370,4043],{"class":3996},[3982,9372,9373,9376,9378,9380,9382,9384,9386,9388,9390],{"class":3984,"line":4921},[3982,9374,9375],{"class":5253},"  retrySync",[3982,9377,9308],{"class":3996},[3982,9379,5166],{"class":4003},[3982,9381,4007],{"class":3996},[3982,9383,4010],{"class":3992},[3982,9385,9317],{"class":3996},[3982,9387,5536],{"class":3988},[3982,9389,9322],{"class":3992},[3982,9391,4043],{"class":3996},[3982,9393,9394,9397,9400,9402,9404],{"class":3984,"line":4927},[3982,9395,9396],{"class":5253},"  loadTasks",[3982,9398,9399],{"class":3996},": () ",[3982,9401,5536],{"class":3988},[3982,9403,9322],{"class":3992},[3982,9405,4043],{"class":3996},[3982,9407,9408],{"class":3984,"line":4933},[3982,9409,4138],{"class":3996},[3982,9411,9412],{"class":3984,"line":4938},[3982,9413,4832],{"emptyLinePlaceholder":4831},[3982,9415,9416,9418,9421,9424,9426,9428,9431,9434,9437,9440,9442,9445,9447,9449],{"class":3984,"line":4943},[3982,9417,5484],{"class":5210},[3982,9419,9420],{"class":3988}," const",[3982,9422,9423],{"class":5239}," useStore",[3982,9425,5243],{"class":3996},[3982,9427,9112],{"class":5253},[3982,9429,9430],{"class":3996},"\u003C",[3982,9432,9433],{"class":3992},"Store",[3982,9435,9436],{"class":3996},">((",[3982,9438,9439],{"class":4003},"set",[3982,9441,3783],{"class":3996},[3982,9443,9444],{"class":4003},"get",[3982,9446,9317],{"class":3996},[3982,9448,5536],{"class":3988},[3982,9450,9451],{"class":3996}," ({\n",[3982,9453,9454,9457],{"class":3984,"line":4949},[3982,9455,9456],{"class":4003},"  tasks:",[3982,9458,9459],{"class":3996}," [],\n",[3982,9461,9462],{"class":3984,"line":4954},[3982,9463,4832],{"emptyLinePlaceholder":4831},[3982,9465,9466,9468,9470,9473,9475],{"class":3984,"line":4960},[3982,9467,9396],{"class":5253},[3982,9469,6753],{"class":4003},[3982,9471,9472],{"class":3996}," () ",[3982,9474,5536],{"class":3988},[3982,9476,5342],{"class":3996},[3982,9478,9479,9481,9484,9486,9489,9491,9494,9496,9499],{"class":3984,"line":4966},[3982,9480,5598],{"class":3988},[3982,9482,9483],{"class":5239}," json",[3982,9485,5243],{"class":3996},[3982,9487,9488],{"class":4003},"storage",[3982,9490,3823],{"class":3996},[3982,9492,9493],{"class":5253},"getString",[3982,9495,5270],{"class":3996},[3982,9497,9498],{"class":4028},"'tasks'",[3982,9500,5375],{"class":3996},[3982,9502,9503,9505,9507,9509],{"class":3984,"line":4972},[3982,9504,6324],{"class":5210},[3982,9506,3778],{"class":3996},[3982,9508,6933],{"class":4003},[3982,9510,5358],{"class":3996},[3982,9512,9513,9516,9519,9521,9524,9526,9529,9531,9533,9535,9538,9540],{"class":3984,"line":4978},[3982,9514,9515],{"class":3988},"      const",[3982,9517,9518],{"class":5239}," tasks",[3982,9520,5243],{"class":3996},[3982,9522,9523],{"class":5239},"JSON",[3982,9525,3823],{"class":3996},[3982,9527,9528],{"class":5253},"parse",[3982,9530,5270],{"class":3996},[3982,9532,6933],{"class":4003},[3982,9534,9317],{"class":3996},[3982,9536,9537],{"class":5210},"as",[3982,9539,9204],{"class":3992},[3982,9541,9300],{"class":3996},[3982,9543,9544,9547,9550,9552],{"class":3984,"line":4983},[3982,9545,9546],{"class":5253},"      set",[3982,9548,9549],{"class":3996},"({ ",[3982,9551,7689],{"class":4003},[3982,9553,6408],{"class":3996},[3982,9555,9556],{"class":3984,"line":4989},[3982,9557,6492],{"class":3996},[3982,9559,9560],{"class":3984,"line":4995},[3982,9561,8502],{"class":3996},[3982,9563,9564],{"class":3984,"line":5001},[3982,9565,4832],{"emptyLinePlaceholder":4831},[3982,9567,9568,9570,9572,9574,9576,9578,9580,9582,9584],{"class":3984,"line":5007},[3982,9569,9305],{"class":5253},[3982,9571,6753],{"class":4003},[3982,9573,3778],{"class":3996},[3982,9575,6479],{"class":4003},[3982,9577,4007],{"class":3996},[3982,9579,4010],{"class":3992},[3982,9581,9317],{"class":3996},[3982,9583,5536],{"class":3988},[3982,9585,5342],{"class":3996},[3982,9587,9588,9590,9593,9595,9597],{"class":3984,"line":5013},[3982,9589,5598],{"class":3988},[3982,9591,9592],{"class":5239}," newTask",[3982,9594,4007],{"class":3996},[3982,9596,9297],{"class":3992},[3982,9598,3997],{"class":3996},[3982,9600,9601,9604,9607,9609,9612,9614,9617,9620,9622,9624],{"class":3984,"line":5018},[3982,9602,9603],{"class":4003},"      id:",[3982,9605,9606],{"class":4028}," `local-",[3982,9608,6237],{"class":3988},[3982,9610,9611],{"class":4003},"Date",[3982,9613,3823],{"class":6242},[3982,9615,9616],{"class":5253},"now",[3982,9618,9619],{"class":6242},"()",[3982,9621,6248],{"class":3988},[3982,9623,6251],{"class":4028},[3982,9625,6287],{"class":3996},[3982,9627,9628,9631],{"class":3984,"line":5024},[3982,9629,9630],{"class":4003},"      text",[3982,9632,6287],{"class":3996},[3982,9634,9635,9638,9641],{"class":3984,"line":5030},[3982,9636,9637],{"class":4003},"      syncStatus:",[3982,9639,9640],{"class":4028}," 'pending'",[3982,9642,6287],{"class":3996},[3982,9644,9645,9648,9651,9653,9655],{"class":3984,"line":5035},[3982,9646,9647],{"class":4003},"      createdAt:",[3982,9649,9650],{"class":4003}," Date",[3982,9652,3823],{"class":3996},[3982,9654,9616],{"class":5253},[3982,9656,6482],{"class":3996},[3982,9658,9659,9661,9664],{"class":3984,"line":8065},[3982,9660,6540],{"class":4003},[3982,9662,9663],{"class":6014}," 0",[3982,9665,6287],{"class":3996},[3982,9667,9668],{"class":3984,"line":8086},[3982,9669,9670],{"class":3996},"    };\n",[3982,9672,9673],{"class":3984,"line":8095},[3982,9674,4832],{"emptyLinePlaceholder":4831},[3982,9676,9677,9679,9681,9684,9686,9688,9690,9692,9695],{"class":3984,"line":8105},[3982,9678,5598],{"class":3988},[3982,9680,9518],{"class":5239},[3982,9682,9683],{"class":3996}," = [...",[3982,9685,9444],{"class":5253},[3982,9687,5555],{"class":3996},[3982,9689,7689],{"class":4003},[3982,9691,3783],{"class":3996},[3982,9693,9694],{"class":4003},"newTask",[3982,9696,9697],{"class":3996},"];\n",[3982,9699,9700,9703,9705,9707],{"class":3984,"line":8110},[3982,9701,9702],{"class":5253},"    set",[3982,9704,9549],{"class":3996},[3982,9706,7689],{"class":4003},[3982,9708,6408],{"class":3996},[3982,9710,9711,9714,9716,9718,9720,9722,9724,9726,9728,9730,9732,9734],{"class":3984,"line":8120},[3982,9712,9713],{"class":4003},"    storage",[3982,9715,3823],{"class":3996},[3982,9717,9439],{"class":5253},[3982,9719,5270],{"class":3996},[3982,9721,9498],{"class":4028},[3982,9723,3783],{"class":3996},[3982,9725,9523],{"class":5239},[3982,9727,3823],{"class":3996},[3982,9729,6300],{"class":5253},[3982,9731,5270],{"class":3996},[3982,9733,7689],{"class":4003},[3982,9735,5584],{"class":3996},[3982,9737,9738],{"class":3984,"line":8128},[3982,9739,8502],{"class":3996},[3982,9741,9742],{"class":3984,"line":8140},[3982,9743,4832],{"emptyLinePlaceholder":4831},[3982,9745,9746,9748,9750,9752,9754,9756,9758,9760,9762,9764,9766,9768,9770],{"class":3984,"line":8153},[3982,9747,9329],{"class":5253},[3982,9749,6753],{"class":4003},[3982,9751,3778],{"class":3996},[3982,9753,5166],{"class":4003},[3982,9755,3783],{"class":3996},[3982,9757,9342],{"class":4003},[3982,9759,3783],{"class":3996},[3982,9761,4182],{"class":4003},[3982,9763,3783],{"class":3996},[3982,9765,3789],{"class":4003},[3982,9767,9317],{"class":3996},[3982,9769,5536],{"class":3988},[3982,9771,5342],{"class":3996},[3982,9773,9774,9776,9778,9780,9782,9784,9786,9788,9791,9794,9797,9799],{"class":3984,"line":8167},[3982,9775,5598],{"class":3988},[3982,9777,9518],{"class":5239},[3982,9779,5243],{"class":3996},[3982,9781,9444],{"class":5253},[3982,9783,5555],{"class":3996},[3982,9785,7689],{"class":4003},[3982,9787,3823],{"class":3996},[3982,9789,9790],{"class":5253},"map",[3982,9792,9793],{"class":3996},"((",[3982,9795,9796],{"class":4003},"task",[3982,9798,9317],{"class":3996},[3982,9800,9801],{"class":3988},"=>\n",[3982,9803,9804,9807,9809,9811,9813],{"class":3984,"line":8183},[3982,9805,9806],{"class":4003},"      task",[3982,9808,3823],{"class":3996},[3982,9810,5166],{"class":4003},[3982,9812,6270],{"class":3996},[3982,9814,9815],{"class":4003},"id\n",[3982,9817,9818,9821,9823,9825,9827,9830,9832,9835,9837,9839,9842,9845,9848,9850,9852,9854],{"class":3984,"line":8208},[3982,9819,9820],{"class":3996},"        ? { ...",[3982,9822,9796],{"class":4003},[3982,9824,3783],{"class":3996},[3982,9826,6402],{"class":4003},[3982,9828,9829],{"class":4003}," status",[3982,9831,3783],{"class":3996},[3982,9833,9834],{"class":4003},"syncError:",[3982,9836,6560],{"class":4003},[3982,9838,3783],{"class":3996},[3982,9840,9841],{"class":4003},"id:",[3982,9843,9844],{"class":4003}," serverId",[3982,9846,9847],{"class":3996}," || ",[3982,9849,9796],{"class":4003},[3982,9851,3823],{"class":3996},[3982,9853,5166],{"class":4003},[3982,9855,7028],{"class":3996},[3982,9857,9858,9861],{"class":3984,"line":8223},[3982,9859,9860],{"class":3996},"        : ",[3982,9862,9863],{"class":4003},"task\n",[3982,9865,9866],{"class":3984,"line":8241},[3982,9867,9868],{"class":3996},"    );\n",[3982,9870,9871,9873,9875,9877],{"class":3984,"line":8271},[3982,9872,9702],{"class":5253},[3982,9874,9549],{"class":3996},[3982,9876,7689],{"class":4003},[3982,9878,6408],{"class":3996},[3982,9880,9881,9883,9885,9887,9889,9891,9893,9895,9897,9899,9901,9903],{"class":3984,"line":8277},[3982,9882,9713],{"class":4003},[3982,9884,3823],{"class":3996},[3982,9886,9439],{"class":5253},[3982,9888,5270],{"class":3996},[3982,9890,9498],{"class":4028},[3982,9892,3783],{"class":3996},[3982,9894,9523],{"class":5239},[3982,9896,3823],{"class":3996},[3982,9898,6300],{"class":5253},[3982,9900,5270],{"class":3996},[3982,9902,7689],{"class":4003},[3982,9904,5584],{"class":3996},[3982,9906,9907],{"class":3984,"line":8294},[3982,9908,8502],{"class":3996},[3982,9910,9911],{"class":3984,"line":8308},[3982,9912,4832],{"emptyLinePlaceholder":4831},[3982,9914,9915,9917,9919,9921,9923,9925,9927],{"class":3984,"line":8313},[3982,9916,9375],{"class":5253},[3982,9918,6753],{"class":4003},[3982,9920,3778],{"class":3996},[3982,9922,5166],{"class":4003},[3982,9924,9317],{"class":3996},[3982,9926,5536],{"class":3988},[3982,9928,5342],{"class":3996},[3982,9930,9931,9933,9935,9937,9939,9941,9943,9945,9947,9949,9951,9953],{"class":3984,"line":8319},[3982,9932,5598],{"class":3988},[3982,9934,9518],{"class":5239},[3982,9936,5243],{"class":3996},[3982,9938,9444],{"class":5253},[3982,9940,5555],{"class":3996},[3982,9942,7689],{"class":4003},[3982,9944,3823],{"class":3996},[3982,9946,9790],{"class":5253},[3982,9948,9793],{"class":3996},[3982,9950,9796],{"class":4003},[3982,9952,9317],{"class":3996},[3982,9954,9801],{"class":3988},[3982,9956,9957,9959,9961,9963,9965],{"class":3984,"line":8325},[3982,9958,9806],{"class":4003},[3982,9960,3823],{"class":3996},[3982,9962,5166],{"class":4003},[3982,9964,6270],{"class":3996},[3982,9966,9815],{"class":4003},[3982,9968,9969,9971,9973,9975,9977,9979,9982,9984,9986,9989,9991],{"class":3984,"line":8330},[3982,9970,9820],{"class":3996},[3982,9972,9796],{"class":4003},[3982,9974,3783],{"class":3996},[3982,9976,6402],{"class":4003},[3982,9978,9640],{"class":4028},[3982,9980,9981],{"class":5210}," as",[3982,9983,4254],{"class":3992},[3982,9985,3783],{"class":3996},[3982,9987,9988],{"class":4003},"retryCount:",[3982,9990,9663],{"class":6014},[3982,9992,7028],{"class":3996},[3982,9994,9995,9997],{"class":3984,"line":8336},[3982,9996,9860],{"class":3996},[3982,9998,9863],{"class":4003},[3982,10000,10001],{"class":3984,"line":8342},[3982,10002,9868],{"class":3996},[3982,10004,10005,10007,10009,10011],{"class":3984,"line":8348},[3982,10006,9702],{"class":5253},[3982,10008,9549],{"class":3996},[3982,10010,7689],{"class":4003},[3982,10012,6408],{"class":3996},[3982,10014,10015,10017,10019,10021,10023,10025,10027,10029,10031,10033,10035,10037],{"class":3984,"line":8354},[3982,10016,9713],{"class":4003},[3982,10018,3823],{"class":3996},[3982,10020,9439],{"class":5253},[3982,10022,5270],{"class":3996},[3982,10024,9498],{"class":4028},[3982,10026,3783],{"class":3996},[3982,10028,9523],{"class":5239},[3982,10030,3823],{"class":3996},[3982,10032,6300],{"class":5253},[3982,10034,5270],{"class":3996},[3982,10036,7689],{"class":4003},[3982,10038,5584],{"class":3996},[3982,10040,10041],{"class":3984,"line":8360},[3982,10042,8502],{"class":3996},[3982,10044,10045],{"class":3984,"line":8366},[3982,10046,10047],{"class":3996},"}));\n",[3973,10049,10053],{"className":10050,"code":10051,"filename":10052,"language":6479,"meta":3978},[7444],"hooks\u002F\n├── useNetworkStatus.ts\n└── useSyncWorker.ts\n","hooks",[3780,10054,10051],{"__ignoreMap":3978},[3973,10056,10059],{"className":3975,"code":10057,"filename":10058,"language":3977,"meta":3978,"style":3978},"import { useEffect, useState } from 'react';\nimport NetInfo from '@react-native-community\u002Fnetinfo';\n\nexport function useNetworkStatus() {\n  const [isOnline, setIsOnline] = useState(true);\n\n  useEffect(() => {\n    NetInfo.fetch().then((state) => setIsOnline(state.isConnected ?? false));\n\n    const unsubscribe = NetInfo.addEventListener((state) => {\n      setIsOnline(state.isConnected ?? false);\n    });\n\n    return unsubscribe;\n  }, []);\n\n  return isOnline;\n}\n","hooks\u002FuseNetworkStatus.ts",[3780,10060,10061,10081,10093,10097,10107,10129,10133,10143,10179,10183,10207,10225,10229,10233,10241,10245,10249,10257],{"__ignoreMap":3978},[3982,10062,10063,10065,10067,10069,10071,10073,10075,10077,10079],{"class":3984,"line":3985},[3982,10064,5211],{"class":5210},[3982,10066,5444],{"class":3996},[3982,10068,5447],{"class":4003},[3982,10070,3783],{"class":3996},[3982,10072,5452],{"class":4003},[3982,10074,5455],{"class":3996},[3982,10076,5458],{"class":5210},[3982,10078,5461],{"class":4028},[3982,10080,4043],{"class":3996},[3982,10082,10083,10085,10087,10089,10091],{"class":3984,"line":4000},[3982,10084,5211],{"class":5210},[3982,10086,5214],{"class":4003},[3982,10088,5217],{"class":5210},[3982,10090,5220],{"class":4028},[3982,10092,4043],{"class":3996},[3982,10094,10095],{"class":3984,"line":4020},[3982,10096,4832],{"emptyLinePlaceholder":4831},[3982,10098,10099,10101,10103,10105],{"class":3984,"line":4046},[3982,10100,5484],{"class":5210},[3982,10102,5487],{"class":3988},[3982,10104,5490],{"class":5253},[3982,10106,5493],{"class":3996},[3982,10108,10109,10111,10113,10115,10117,10119,10121,10123,10125,10127],{"class":3984,"line":4069},[3982,10110,5498],{"class":3988},[3982,10112,5501],{"class":3996},[3982,10114,5504],{"class":5239},[3982,10116,3783],{"class":3996},[3982,10118,5509],{"class":5239},[3982,10120,5512],{"class":3996},[3982,10122,5452],{"class":5253},[3982,10124,5270],{"class":3996},[3982,10126,5519],{"class":3988},[3982,10128,5375],{"class":3996},[3982,10130,10131],{"class":3984,"line":4086},[3982,10132,4832],{"emptyLinePlaceholder":4831},[3982,10134,10135,10137,10139,10141],{"class":3984,"line":4103},[3982,10136,5530],{"class":5253},[3982,10138,5533],{"class":3996},[3982,10140,5536],{"class":3988},[3982,10142,5342],{"class":3996},[3982,10144,10145,10147,10149,10151,10153,10155,10157,10159,10161,10163,10165,10167,10169,10171,10173,10175,10177],{"class":3984,"line":4119},[3982,10146,5548],{"class":4003},[3982,10148,3823],{"class":3996},[3982,10150,5254],{"class":5253},[3982,10152,5555],{"class":3996},[3982,10154,5558],{"class":5253},[3982,10156,9793],{"class":3996},[3982,10158,5273],{"class":4003},[3982,10160,9317],{"class":3996},[3982,10162,5536],{"class":3988},[3982,10164,5567],{"class":5253},[3982,10166,5270],{"class":3996},[3982,10168,5273],{"class":4003},[3982,10170,3823],{"class":3996},[3982,10172,5278],{"class":4003},[3982,10174,5578],{"class":3996},[3982,10176,5581],{"class":3988},[3982,10178,5584],{"class":3996},[3982,10180,10181],{"class":3984,"line":4135},[3982,10182,4832],{"emptyLinePlaceholder":4831},[3982,10184,10185,10187,10189,10191,10193,10195,10197,10199,10201,10203,10205],{"class":3984,"line":4859},[3982,10186,5598],{"class":3988},[3982,10188,5322],{"class":5239},[3982,10190,5243],{"class":3996},[3982,10192,5327],{"class":4003},[3982,10194,3823],{"class":3996},[3982,10196,5332],{"class":5253},[3982,10198,9793],{"class":3996},[3982,10200,5273],{"class":4003},[3982,10202,9317],{"class":3996},[3982,10204,5536],{"class":3988},[3982,10206,5342],{"class":3996},[3982,10208,10209,10211,10213,10215,10217,10219,10221,10223],{"class":3984,"line":4865},[3982,10210,5621],{"class":5253},[3982,10212,5270],{"class":3996},[3982,10214,5273],{"class":4003},[3982,10216,3823],{"class":3996},[3982,10218,5278],{"class":4003},[3982,10220,5578],{"class":3996},[3982,10222,5581],{"class":3988},[3982,10224,5375],{"class":3996},[3982,10226,10227],{"class":3984,"line":4871},[3982,10228,5640],{"class":3996},[3982,10230,10231],{"class":3984,"line":4877},[3982,10232,4832],{"emptyLinePlaceholder":4831},[3982,10234,10235,10237,10239],{"class":3984,"line":4883},[3982,10236,5649],{"class":5210},[3982,10238,5322],{"class":4003},[3982,10240,4043],{"class":3996},[3982,10242,10243],{"class":3984,"line":4888},[3982,10244,5658],{"class":3996},[3982,10246,10247],{"class":3984,"line":4893},[3982,10248,4832],{"emptyLinePlaceholder":4831},[3982,10250,10251,10253,10255],{"class":3984,"line":4899},[3982,10252,5667],{"class":5210},[3982,10254,5670],{"class":4003},[3982,10256,4043],{"class":3996},[3982,10258,10259],{"class":3984,"line":4905},[3982,10260,4852],{"class":3996},[3973,10262,10265],{"className":3975,"code":10263,"filename":10264,"language":3977,"meta":3978,"style":3978},"import { useEffect } from 'react';\nimport { useStore } from '..\u002Fstore\u002FuseStore';\nimport { useNetworkStatus } from '.\u002FuseNetworkStatus';\n\nexport function useSyncWorker() {\n  const { tasks, updateTaskStatus } = useStore();\n  const isOnline = useNetworkStatus();\n\n  useEffect(() => {\n    if (!isOnline) return;\n\n    const interval = setInterval(() => {\n      syncPendingTasks();\n    }, 5000); \u002F\u002F Кожні 5 секунд\n\n    \u002F\u002F Одразу спробувати при появі мережі\n    syncPendingTasks();\n\n    return () => clearInterval(interval);\n  }, [isOnline, tasks]);\n\n  async function syncPendingTasks() {\n    const pending = tasks.filter((t) => t.syncStatus === 'pending');\n\n    for (const task of pending) {\n      updateTaskStatus(task.id, 'syncing');\n\n      try {\n        \u002F\u002F Mock API (замість fetch)\n        await mockApiCall(task);\n\n        \u002F\u002F Успіх\n        const serverId = `srv-${Math.random().toString(36).slice(2, 9)}`;\n        updateTaskStatus(task.id, 'synced', serverId);\n      } catch (error) {\n        \u002F\u002F Помилка\n        updateTaskStatus(task.id, 'error', undefined, (error as Error).message);\n      }\n    }\n  }\n\n  async function mockApiCall(task: any): Promise\u003Cvoid> {\n    return new Promise((resolve, reject) => {\n      setTimeout(() => {\n        \u002F\u002F 80% успіх, 20% помилка (для демо)\n        if (Math.random() > 0.2) {\n          resolve();\n        } else {\n          reject(new Error('Server unavailable'));\n        }\n      }, 1000); \u002F\u002F Імітація мережевої затримки\n    });\n  }\n}\n","hooks\u002FuseSyncWorker.ts",[3780,10266,10267,10283,10299,10316,10320,10331,10350,10362,10366,10376,10392,10396,10414,10421,10435,10439,10444,10451,10455,10473,10487,10491,10503,10541,10545,10564,10583,10587,10594,10599,10613,10617,10622,10674,10697,10710,10715,10752,10757,10761,10765,10769,10800,10823,10834,10839,10860,10867,10876,10894,10899,10911,10915,10919],{"__ignoreMap":3978},[3982,10268,10269,10271,10273,10275,10277,10279,10281],{"class":3984,"line":3985},[3982,10270,5211],{"class":5210},[3982,10272,5444],{"class":3996},[3982,10274,5447],{"class":4003},[3982,10276,5455],{"class":3996},[3982,10278,5458],{"class":5210},[3982,10280,5461],{"class":4028},[3982,10282,4043],{"class":3996},[3982,10284,10285,10287,10289,10291,10293,10295,10297],{"class":3984,"line":4000},[3982,10286,5211],{"class":5210},[3982,10288,5444],{"class":3996},[3982,10290,7596],{"class":4003},[3982,10292,5455],{"class":3996},[3982,10294,5458],{"class":5210},[3982,10296,7603],{"class":4028},[3982,10298,4043],{"class":3996},[3982,10300,10301,10303,10305,10307,10309,10311,10314],{"class":3984,"line":4020},[3982,10302,5211],{"class":5210},[3982,10304,5444],{"class":3996},[3982,10306,5707],{"class":4003},[3982,10308,5455],{"class":3996},[3982,10310,5458],{"class":5210},[3982,10312,10313],{"class":4028}," '.\u002FuseNetworkStatus'",[3982,10315,4043],{"class":3996},[3982,10317,10318],{"class":3984,"line":4046},[3982,10319,4832],{"emptyLinePlaceholder":4831},[3982,10321,10322,10324,10326,10329],{"class":3984,"line":4069},[3982,10323,5484],{"class":5210},[3982,10325,5487],{"class":3988},[3982,10327,10328],{"class":5253}," useSyncWorker",[3982,10330,5493],{"class":3996},[3982,10332,10333,10335,10337,10339,10341,10344,10346,10348],{"class":3984,"line":4086},[3982,10334,5498],{"class":3988},[3982,10336,5444],{"class":3996},[3982,10338,7689],{"class":5239},[3982,10340,3783],{"class":3996},[3982,10342,10343],{"class":5239},"updateTaskStatus",[3982,10345,7702],{"class":3996},[3982,10347,7596],{"class":5253},[3982,10349,5257],{"class":3996},[3982,10351,10352,10354,10356,10358,10360],{"class":3984,"line":4103},[3982,10353,5498],{"class":3988},[3982,10355,5670],{"class":5239},[3982,10357,5243],{"class":3996},[3982,10359,5707],{"class":5253},[3982,10361,5257],{"class":3996},[3982,10363,10364],{"class":3984,"line":4119},[3982,10365,4832],{"emptyLinePlaceholder":4831},[3982,10367,10368,10370,10372,10374],{"class":3984,"line":4135},[3982,10369,5530],{"class":5253},[3982,10371,5533],{"class":3996},[3982,10373,5536],{"class":3988},[3982,10375,5342],{"class":3996},[3982,10377,10378,10380,10383,10385,10387,10390],{"class":3984,"line":4859},[3982,10379,6324],{"class":5210},[3982,10381,10382],{"class":3996}," (!",[3982,10384,5504],{"class":4003},[3982,10386,9317],{"class":3996},[3982,10388,10389],{"class":5210},"return",[3982,10391,4043],{"class":3996},[3982,10393,10394],{"class":3984,"line":4865},[3982,10395,4832],{"emptyLinePlaceholder":4831},[3982,10397,10398,10400,10403,10405,10408,10410,10412],{"class":3984,"line":4871},[3982,10399,5598],{"class":3988},[3982,10401,10402],{"class":5239}," interval",[3982,10404,5243],{"class":3996},[3982,10406,10407],{"class":5253},"setInterval",[3982,10409,5533],{"class":3996},[3982,10411,5536],{"class":3988},[3982,10413,5342],{"class":3996},[3982,10415,10416,10419],{"class":3984,"line":4877},[3982,10417,10418],{"class":5253},"      syncPendingTasks",[3982,10420,5257],{"class":3996},[3982,10422,10423,10426,10429,10432],{"class":3984,"line":4883},[3982,10424,10425],{"class":3996},"    }, ",[3982,10427,10428],{"class":6014},"5000",[3982,10430,10431],{"class":3996},"); ",[3982,10433,10434],{"class":4016},"\u002F\u002F Кожні 5 секунд\n",[3982,10436,10437],{"class":3984,"line":4888},[3982,10438,4832],{"emptyLinePlaceholder":4831},[3982,10440,10441],{"class":3984,"line":4893},[3982,10442,10443],{"class":4016},"    \u002F\u002F Одразу спробувати при появі мережі\n",[3982,10445,10446,10449],{"class":3984,"line":4899},[3982,10447,10448],{"class":5253},"    syncPendingTasks",[3982,10450,5257],{"class":3996},[3982,10452,10453],{"class":3984,"line":4905},[3982,10454,4832],{"emptyLinePlaceholder":4831},[3982,10456,10457,10459,10461,10463,10466,10468,10471],{"class":3984,"line":4911},[3982,10458,5649],{"class":5210},[3982,10460,9472],{"class":3996},[3982,10462,5536],{"class":3988},[3982,10464,10465],{"class":5253}," clearInterval",[3982,10467,5270],{"class":3996},[3982,10469,10470],{"class":4003},"interval",[3982,10472,5375],{"class":3996},[3982,10474,10475,10478,10480,10482,10484],{"class":3984,"line":4916},[3982,10476,10477],{"class":3996},"  }, [",[3982,10479,5504],{"class":4003},[3982,10481,3783],{"class":3996},[3982,10483,7689],{"class":4003},[3982,10485,10486],{"class":3996},"]);\n",[3982,10488,10489],{"class":3984,"line":4921},[3982,10490,4832],{"emptyLinePlaceholder":4831},[3982,10492,10493,10496,10498,10501],{"class":3984,"line":4927},[3982,10494,10495],{"class":3988},"  async",[3982,10497,5487],{"class":3988},[3982,10499,10500],{"class":5253}," syncPendingTasks",[3982,10502,5493],{"class":3996},[3982,10504,10505,10507,10510,10512,10514,10516,10519,10521,10524,10526,10528,10531,10533,10535,10537,10539],{"class":3984,"line":4933},[3982,10506,5598],{"class":3988},[3982,10508,10509],{"class":5239}," pending",[3982,10511,5243],{"class":3996},[3982,10513,7689],{"class":4003},[3982,10515,3823],{"class":3996},[3982,10517,10518],{"class":5253},"filter",[3982,10520,9793],{"class":3996},[3982,10522,10523],{"class":4003},"t",[3982,10525,9317],{"class":3996},[3982,10527,5536],{"class":3988},[3982,10529,10530],{"class":4003}," t",[3982,10532,3823],{"class":3996},[3982,10534,3818],{"class":4003},[3982,10536,6270],{"class":3996},[3982,10538,4265],{"class":4028},[3982,10540,5375],{"class":3996},[3982,10542,10543],{"class":3984,"line":4938},[3982,10544,4832],{"emptyLinePlaceholder":4831},[3982,10546,10547,10550,10552,10554,10557,10560,10562],{"class":3984,"line":4943},[3982,10548,10549],{"class":5210},"    for",[3982,10551,3778],{"class":3996},[3982,10553,5236],{"class":3988},[3982,10555,10556],{"class":5239}," task",[3982,10558,10559],{"class":3988}," of",[3982,10561,10509],{"class":4003},[3982,10563,5358],{"class":3996},[3982,10565,10566,10569,10571,10573,10575,10577,10579,10581],{"class":3984,"line":4949},[3982,10567,10568],{"class":5253},"      updateTaskStatus",[3982,10570,5270],{"class":3996},[3982,10572,9796],{"class":4003},[3982,10574,3823],{"class":3996},[3982,10576,5166],{"class":4003},[3982,10578,3783],{"class":3996},[3982,10580,4275],{"class":4028},[3982,10582,5375],{"class":3996},[3982,10584,10585],{"class":3984,"line":4954},[3982,10586,4832],{"emptyLinePlaceholder":4831},[3982,10588,10589,10592],{"class":3984,"line":4960},[3982,10590,10591],{"class":5210},"      try",[3982,10593,5342],{"class":3996},[3982,10595,10596],{"class":3984,"line":4966},[3982,10597,10598],{"class":4016},"        \u002F\u002F Mock API (замість fetch)\n",[3982,10600,10601,10604,10607,10609,10611],{"class":3984,"line":4972},[3982,10602,10603],{"class":5210},"        await",[3982,10605,10606],{"class":5253}," mockApiCall",[3982,10608,5270],{"class":3996},[3982,10610,9796],{"class":4003},[3982,10612,5375],{"class":3996},[3982,10614,10615],{"class":3984,"line":4978},[3982,10616,4832],{"emptyLinePlaceholder":4831},[3982,10618,10619],{"class":3984,"line":4983},[3982,10620,10621],{"class":4016},"        \u002F\u002F Успіх\n",[3982,10623,10624,10627,10629,10631,10634,10636,10638,10640,10642,10644,10647,10649,10652,10654,10657,10659,10661,10663,10666,10668,10670,10672],{"class":3984,"line":4989},[3982,10625,10626],{"class":3988},"        const",[3982,10628,9844],{"class":5239},[3982,10630,5243],{"class":3996},[3982,10632,10633],{"class":4028},"`srv-",[3982,10635,6237],{"class":3988},[3982,10637,5986],{"class":4003},[3982,10639,3823],{"class":6242},[3982,10641,6647],{"class":5253},[3982,10643,5555],{"class":6242},[3982,10645,10646],{"class":5253},"toString",[3982,10648,5270],{"class":6242},[3982,10650,10651],{"class":6014},"36",[3982,10653,4471],{"class":6242},[3982,10655,10656],{"class":5253},"slice",[3982,10658,5270],{"class":6242},[3982,10660,5937],{"class":6014},[3982,10662,3783],{"class":6242},[3982,10664,10665],{"class":6014},"9",[3982,10667,7431],{"class":6242},[3982,10669,6248],{"class":3988},[3982,10671,6251],{"class":4028},[3982,10673,4043],{"class":3996},[3982,10675,10676,10679,10681,10683,10685,10687,10689,10691,10693,10695],{"class":3984,"line":4995},[3982,10677,10678],{"class":5253},"        updateTaskStatus",[3982,10680,5270],{"class":3996},[3982,10682,9796],{"class":4003},[3982,10684,3823],{"class":3996},[3982,10686,5166],{"class":4003},[3982,10688,3783],{"class":3996},[3982,10690,4285],{"class":4028},[3982,10692,3783],{"class":3996},[3982,10694,4182],{"class":4003},[3982,10696,5375],{"class":3996},[3982,10698,10699,10702,10704,10706,10708],{"class":3984,"line":5001},[3982,10700,10701],{"class":3996},"      } ",[3982,10703,6499],{"class":5210},[3982,10705,3778],{"class":3996},[3982,10707,3789],{"class":4003},[3982,10709,5358],{"class":3996},[3982,10711,10712],{"class":3984,"line":5007},[3982,10713,10714],{"class":4016},"        \u002F\u002F Помилка\n",[3982,10716,10717,10719,10721,10723,10725,10727,10729,10731,10733,10736,10739,10741,10743,10746,10748,10750],{"class":3984,"line":5013},[3982,10718,10678],{"class":5253},[3982,10720,5270],{"class":3996},[3982,10722,9796],{"class":4003},[3982,10724,3823],{"class":3996},[3982,10726,5166],{"class":4003},[3982,10728,3783],{"class":3996},[3982,10730,4295],{"class":4028},[3982,10732,3783],{"class":3996},[3982,10734,10735],{"class":3988},"undefined",[3982,10737,10738],{"class":3996},", (",[3982,10740,3789],{"class":4003},[3982,10742,9981],{"class":5210},[3982,10744,10745],{"class":3992}," Error",[3982,10747,4471],{"class":3996},[3982,10749,6565],{"class":4003},[3982,10751,5375],{"class":3996},[3982,10753,10754],{"class":3984,"line":5018},[3982,10755,10756],{"class":3996},"      }\n",[3982,10758,10759],{"class":3984,"line":5024},[3982,10760,6492],{"class":3996},[3982,10762,10763],{"class":3984,"line":5030},[3982,10764,5417],{"class":3996},[3982,10766,10767],{"class":3984,"line":5035},[3982,10768,4832],{"emptyLinePlaceholder":4831},[3982,10770,10771,10773,10775,10777,10779,10781,10783,10786,10789,10792,10794,10797],{"class":3984,"line":8065},[3982,10772,10495],{"class":3988},[3982,10774,5487],{"class":3988},[3982,10776,10606],{"class":5253},[3982,10778,5270],{"class":3996},[3982,10780,9796],{"class":4003},[3982,10782,4007],{"class":3996},[3982,10784,10785],{"class":3992},"any",[3982,10787,10788],{"class":3996},"): ",[3982,10790,10791],{"class":3992},"Promise",[3982,10793,9430],{"class":3996},[3982,10795,10796],{"class":3992},"void",[3982,10798,10799],{"class":3996},"> {\n",[3982,10801,10802,10804,10806,10808,10810,10812,10814,10817,10819,10821],{"class":3984,"line":8086},[3982,10803,5649],{"class":5210},[3982,10805,6180],{"class":3988},[3982,10807,6183],{"class":3992},[3982,10809,9793],{"class":3996},[3982,10811,6188],{"class":4003},[3982,10813,3783],{"class":3996},[3982,10815,10816],{"class":4003},"reject",[3982,10818,9317],{"class":3996},[3982,10820,5536],{"class":3988},[3982,10822,5342],{"class":3996},[3982,10824,10825,10828,10830,10832],{"class":3984,"line":8095},[3982,10826,10827],{"class":5253},"      setTimeout",[3982,10829,5533],{"class":3996},[3982,10831,5536],{"class":3988},[3982,10833,5342],{"class":3996},[3982,10835,10836],{"class":3984,"line":8105},[3982,10837,10838],{"class":4016},"        \u002F\u002F 80% успіх, 20% помилка (для демо)\n",[3982,10840,10841,10844,10846,10848,10850,10852,10855,10858],{"class":3984,"line":8110},[3982,10842,10843],{"class":5210},"        if",[3982,10845,3778],{"class":3996},[3982,10847,5986],{"class":4003},[3982,10849,3823],{"class":3996},[3982,10851,6647],{"class":5253},[3982,10853,10854],{"class":3996},"() > ",[3982,10856,10857],{"class":6014},"0.2",[3982,10859,5358],{"class":3996},[3982,10861,10862,10865],{"class":3984,"line":8120},[3982,10863,10864],{"class":5253},"          resolve",[3982,10866,5257],{"class":3996},[3982,10868,10869,10872,10874],{"class":3984,"line":8128},[3982,10870,10871],{"class":3996},"        } ",[3982,10873,5395],{"class":5210},[3982,10875,5342],{"class":3996},[3982,10877,10878,10881,10883,10885,10887,10889,10892],{"class":3984,"line":8140},[3982,10879,10880],{"class":5253},"          reject",[3982,10882,5270],{"class":3996},[3982,10884,9155],{"class":3988},[3982,10886,10745],{"class":5253},[3982,10888,5270],{"class":3996},[3982,10890,10891],{"class":4028},"'Server unavailable'",[3982,10893,5584],{"class":3996},[3982,10895,10896],{"class":3984,"line":8153},[3982,10897,10898],{"class":3996},"        }\n",[3982,10900,10901,10904,10906,10908],{"class":3984,"line":8167},[3982,10902,10903],{"class":3996},"      }, ",[3982,10905,6653],{"class":6014},[3982,10907,10431],{"class":3996},[3982,10909,10910],{"class":4016},"\u002F\u002F Імітація мережевої затримки\n",[3982,10912,10913],{"class":3984,"line":8183},[3982,10914,5640],{"class":3996},[3982,10916,10917],{"class":3984,"line":8208},[3982,10918,5417],{"class":3996},[3982,10920,10921],{"class":3984,"line":8223},[3982,10922,4852],{"class":3996},[3973,10924,10928],{"className":10925,"code":10926,"filename":10927,"language":6479,"meta":3978},[7444],"{\n  \"name\": \"offline-checklist\",\n  \"version\": \"1.0.0\",\n  \"main\": \"expo-router\u002Fentry\",\n  \"scripts\": {\n    \"start\": \"expo start\",\n    \"android\": \"expo start --android\",\n    \"ios\": \"expo start --ios\"\n  },\n  \"dependencies\": {\n    \"expo\": \"~52.0.0\",\n    \"expo-router\": \"~4.0.0\",\n    \"react\": \"18.3.1\",\n    \"react-native\": \"0.76.5\",\n    \"react-native-mmkv\": \"^3.0.0\",\n    \"@react-native-community\u002Fnetinfo\": \"^11.4.0\",\n    \"zustand\": \"^5.0.0\"\n  },\n  \"devDependencies\": {\n    \"@types\u002Freact\": \"~18.3.0\",\n    \"typescript\": \"~5.3.0\"\n  }\n}\n","package.json",[3780,10929,10926],{"__ignoreMap":3978},[3836,10931],{},[3843,10933,10935],{"id":10934},"покрокова-інструкція","Покрокова інструкція",[10937,10938,10939,10944,10976,10980,11014,11018,11024,11059,11067,11090,11094,11111,11115,11129,11140,11144,11158,11162],"steps",{},[10940,10941,10943],"h4",{"id":10942},"крок-1-створити-проєкт","Крок 1. Створити проєкт",[3973,10945,10949],{"className":10946,"code":10947,"language":10948,"meta":3978,"style":3978},"language-bash shiki shiki-themes light-plus dark-plus dark-plus","npx create-expo-app@latest offline-checklist --template blank-typescript\ncd offline-checklist\n","bash",[3780,10950,10951,10968],{"__ignoreMap":3978},[3982,10952,10953,10956,10959,10962,10965],{"class":3984,"line":3985},[3982,10954,10955],{"class":5253},"npx",[3982,10957,10958],{"class":4028}," create-expo-app@latest",[3982,10960,10961],{"class":4028}," offline-checklist",[3982,10963,10964],{"class":3988}," --template",[3982,10966,10967],{"class":4028}," blank-typescript\n",[3982,10969,10970,10973],{"class":3984,"line":4000},[3982,10971,10972],{"class":5253},"cd",[3982,10974,10975],{"class":4028}," offline-checklist\n",[10940,10977,10979],{"id":10978},"крок-2-встановити-залежності","Крок 2. Встановити залежності",[3973,10981,10983],{"className":10946,"code":10982,"language":10948,"meta":3978,"style":3978},"npx expo install expo-router react-native-mmkv @react-native-community\u002Fnetinfo\nnpm install zustand\n",[3780,10984,10985,11004],{"__ignoreMap":3978},[3982,10986,10987,10989,10992,10995,10998,11001],{"class":3984,"line":3985},[3982,10988,10955],{"class":5253},[3982,10990,10991],{"class":4028}," expo",[3982,10993,10994],{"class":4028}," install",[3982,10996,10997],{"class":4028}," expo-router",[3982,10999,11000],{"class":4028}," react-native-mmkv",[3982,11002,11003],{"class":4028}," @react-native-community\u002Fnetinfo\n",[3982,11005,11006,11009,11011],{"class":3984,"line":4000},[3982,11007,11008],{"class":5253},"npm",[3982,11010,10994],{"class":4028},[3982,11012,11013],{"class":4028}," zustand\n",[10940,11015,11017],{"id":11016},"крок-3-налаштувати-expo-router","Крок 3. Налаштувати Expo Router",[3743,11019,7109,11020,11023],{},[3780,11021,11022],{},"app.json"," додати:",[3973,11025,11027],{"className":6931,"code":11026,"language":6933,"meta":3978,"style":3978},"{\n  \"expo\": {\n    \"scheme\": \"offline-checklist\"\n  }\n}\n",[3780,11028,11029,11033,11041,11051,11055],{"__ignoreMap":3978},[3982,11030,11031],{"class":3984,"line":3985},[3982,11032,6765],{"class":3996},[3982,11034,11035,11038],{"class":3984,"line":4000},[3982,11036,11037],{"class":6770},"  \"expo\"",[3982,11039,11040],{"class":3996},": {\n",[3982,11042,11043,11046,11048],{"class":3984,"line":4020},[3982,11044,11045],{"class":6770},"    \"scheme\"",[3982,11047,4007],{"class":3996},[3982,11049,11050],{"class":4028},"\"offline-checklist\"\n",[3982,11052,11053],{"class":3984,"line":4046},[3982,11054,5417],{"class":3996},[3982,11056,11057],{"class":3984,"line":4069},[3982,11058,4852],{"class":3996},[3743,11060,7109,11061,11063,11064,6753],{},[3780,11062,10927],{}," змінити ",[3780,11065,11066],{},"main",[3973,11068,11070],{"className":6931,"code":11069,"language":6933,"meta":3978,"style":3978},"{\n  \"main\": \"expo-router\u002Fentry\"\n}\n",[3780,11071,11072,11076,11086],{"__ignoreMap":3978},[3982,11073,11074],{"class":3984,"line":3985},[3982,11075,6765],{"class":3996},[3982,11077,11078,11081,11083],{"class":3984,"line":4000},[3982,11079,11080],{"class":6770},"  \"main\"",[3982,11082,4007],{"class":3996},[3982,11084,11085],{"class":4028},"\"expo-router\u002Fentry\"\n",[3982,11087,11088],{"class":3984,"line":4020},[3982,11089,4852],{"class":3996},[10940,11091,11093],{"id":11092},"крок-4-створити-структуру-файлів","Крок 4. Створити структуру файлів",[3743,11095,11096,11097,3783,11100,3783,11103,11106,11107,11110],{},"Створити папки ",[3780,11098,11099],{},"app\u002F",[3780,11101,11102],{},"store\u002F",[3780,11104,11105],{},"hooks\u002F"," і файли як у ",[3780,11108,11109],{},"::code-tree"," вище.",[10940,11112,11114],{"id":11113},"крок-5-запустити-застосунок","Крок 5. Запустити застосунок",[3973,11116,11118],{"className":10946,"code":11117,"language":10948,"meta":3978,"style":3978},"npx expo start\n",[3780,11119,11120],{"__ignoreMap":3978},[3982,11121,11122,11124,11126],{"class":3984,"line":3985},[3982,11123,10955],{"class":5253},[3982,11125,10991],{"class":4028},[3982,11127,11128],{"class":4028}," start\n",[3743,11130,11131,11132,11135,11136,11139],{},"Натисніть ",[3780,11133,11134],{},"i"," (iOS) або ",[3780,11137,11138],{},"a"," (Android).",[10940,11141,11143],{"id":11142},"крок-6-перевірити-офлайн-режим","Крок 6. Перевірити офлайн-режим",[3927,11145,11146,11149,11152,11155],{},[3765,11147,11148],{},"Додати кілька завдань з увімкненою мережею → бачите badge «✅ Синхронізовано».",[3765,11150,11151],{},"Вимкнути Wi-Fi на пристрої.",[3765,11153,11154],{},"Додати нове завдання → badge «⏳ Не синхронізовано».",[3765,11156,11157],{},"Увімкнути Wi-Fi → через 5 секунд badge змінюється на «✅ Синхронізовано».",[10940,11159,11161],{"id":11160},"крок-7-перевірити-retry","Крок 7. Перевірити retry",[3743,11163,11164],{},"Оскільки mock API має 20% шанс помилки, іноді завдання отримає badge «❌ Помилка». Натисніть «Повторити» → статус змінюється на «⏳ Не синхронізовано», і worker спробує знову.",[3836,11166],{},[3843,11168,11170],{"id":11169},"що-відбувається-під-капотом","Що відбувається під капотом",[3927,11172,11173,11194,11222,11237,11251],{},[3765,11174,11175,11178],{},[3747,11176,11177],{},"Додавання завдання:",[3762,11179,11180,11191],{},[3765,11181,11182,11185,11186,4338,11188,11190],{},[3780,11183,11184],{},"addTask(text)"," створює об'єкт ",[3780,11187,9297],{},[3780,11189,4151],{},", зберігає в MMKV.",[3765,11192,11193],{},"UI одразу показує нове завдання в списку.",[3765,11195,11196,11199],{},[3747,11197,11198],{},"Фонова синхронізація:",[3762,11200,11201,11209,11215],{},[3765,11202,11203,11205,11206,11208],{},[3780,11204,5091],{}," запускає ",[3780,11207,10407],{}," кожні 5 секунд.",[3765,11210,11211,11212,3823],{},"Фільтрує ",[3780,11213,11214],{},"tasks.filter(t => t.syncStatus === 'pending')",[3765,11216,11217,11218,11221],{},"Для кожного pending-завдання викликає ",[3780,11219,11220],{},"mockApiCall"," (імітація fetch).",[3765,11223,11224,11226],{},[3747,11225,4333],{},[3762,11227,11228,11234],{},[3765,11229,11230,11233],{},[3780,11231,11232],{},"updateTaskStatus(id, 'synced', serverId)"," оновлює задачу в сховищі.",[3765,11235,11236],{},"Badge змінюється на «✅ Синхронізовано».",[3765,11238,11239,11241],{},[3747,11240,4353],{},[3762,11242,11243,11248],{},[3765,11244,11245,3823],{},[3780,11246,11247],{},"updateTaskStatus(id, 'error', undefined, errorMessage)",[3765,11249,11250],{},"Badge «❌ Помилка» + кнопка «Повторити».",[3765,11252,11253,11256],{},[3747,11254,11255],{},"Retry:",[3762,11257,11258,11270],{},[3765,11259,11260,11261,11264,11265,3783,11267,3823],{},"Користувач натискає «Повторити» → ",[3780,11262,11263],{},"retrySync(id)"," скидає статус на ",[3780,11266,4265],{},[3780,11268,11269],{},"retryCount: 0",[3765,11271,11272],{},"Worker знову обробить цю задачу при наступному циклі.",[3825,11274,11275,11276,11279,11280,11282,11283,11286],{},"Цей міні-проєкт показує ",[3747,11277,11278],{},"весь життєвий цикл offline-sync",": створення → pending → syncing → synced\u002Ferror → retry. У реальному застосунку замість ",[3780,11281,11220],{}," буде ",[3780,11284,11285],{},"fetch('\u002Fapi\u002Ftasks')",", а замість MMKV — SQLite з outbox-таблицею.",[3836,11288],{},[3843,11290,11292],{"id":11291},"критерій-готово","Критерій «Готово»",[3762,11294,11297,11305,11311,11317,11323,11329],{"className":11295},[11296],"contains-task-list",[3765,11298,11301,11304],{"className":11299},[11300],"task-list-item",[7985,11302],{"disabled":4831,"type":11303},"checkbox"," Застосунок запускається на iOS або Android.",[3765,11306,11308,11310],{"className":11307},[11300],[7985,11309],{"disabled":4831,"type":11303}," Додавання завдань працює онлайн і офлайн.",[3765,11312,11314,11316],{"className":11313},[11300],[7985,11315],{"disabled":4831,"type":11303}," Офлайн-banner з'являється, коли немає мережі.",[3765,11318,11320,11322],{"className":11319},[11300],[7985,11321],{"disabled":4831,"type":11303}," Badge синхронізації показує актуальний статус.",[3765,11324,11326,11328],{"className":11325},[11300],[7985,11327],{"disabled":4831,"type":11303}," При помилці можна натиснути «Повторити».",[3765,11330,11332,11334],{"className":11331},[11300],[7985,11333],{"disabled":4831,"type":11303}," Після перезапуску застосунку завдання лишаються (MMKV persistence).",[3836,11336],{},[3738,11338,11340],{"id":11339},"частина-3-наскрізний-проєкт-nomad","Частина 3. Наскрізний проєкт «Nomad»",[3843,11342,11344],{"id":11343},"навіщо-користувачу","Навіщо користувачу",[3743,11346,11347],{},"Ви плануєте відпустку: відкриваєте Nomad у літаку (режим польоту, мережі немає) і створюєте нову поїздку «Париж 2026». Додаєте кілька місць, які хочете відвідати: «Ейфелева вежа», «Лувр», «Монмартр». Застосунок працює миттєво — ви бачите всі зміни одразу, хоч інтернету й немає.",[3743,11349,11350,11351,11354],{},"Коли літак приземляється і телефон підключається до мережі, Nomad ",[3747,11352,11353],{},"автоматично"," синхронізує всі ваші поїздки та місця з сервером. Ви навіть не помічаєте цього процесу — просто іноді бачите маленьку іконку «хмаринка» біля картки, яка через кілька секунд зникає.",[3743,11356,11357],{},"Якщо щось пішло не так (сервер недоступний, конфлікт версій), застасунок покаже зрозуміле повідомлення і дасть можливість повторити синхронізацію одним дотиком.",[3743,11359,11360,11363],{},[3747,11361,11362],{},"У цій статті"," ми додамо в Nomad:",[3762,11365,11366,11372,11378,11384,11387,11390],{},[3765,11367,11368,11369,11371],{},"Поле ",[3780,11370,3818],{}," для кожної поїздки та місця.",[3765,11373,11374,11375,11377],{},"Таблицю ",[3780,11376,4157],{}," у SQLite для черги операцій.",[3765,11379,11380,11381,11383],{},"Фоновий ",[3780,11382,5091],{},", який автоматично відправляє зміни на API.",[3765,11385,11386],{},"Offline-banner у header списку поїздок.",[3765,11388,11389],{},"Sync-badge на кожній картці поїздки.",[3765,11391,11392],{},"Кнопку «Повторити» для записів із помилкою.",[3836,11394],{},[3843,11396,11398],{"id":11397},"нитка-проєкту","Нитка проєкту",[10940,11400,11402],{"id":11401},"уже-є-з-попередніх-статей","Уже є (з попередніх статей)",[3762,11404,11405,11411,11417,11423,11429,11441],{},[3765,11406,11407,11410],{},[3747,11408,11409],{},"Теми"," (світла\u002Fтемна) з чіпами перемикача (стаття 08).",[3765,11412,11413,11416],{},[3747,11414,11415],{},"Список поїздок"," з mock-даними, FlatList, sticky CTA «Нова поїздка» (статті 06–09).",[3765,11418,11419,11422],{},[3747,11420,11421],{},"Форма створення поїздки"," з валідацією через React Hook Form + Zod (стаття 10).",[3765,11424,11425,11428],{},[3747,11426,11427],{},"Навігація"," через Expo Router: tabs (Поїздки \u002F Профіль), stack деталей поїздки, модальне вікно створення (статті 11–12).",[3765,11430,11431,11434,11435,3783,11437,11440],{},[3747,11432,11433],{},"Мережеві запити"," через RTK Query: ",[3780,11436,5146],{},[3780,11438,11439],{},"useCreateTripMutation()"," (статті 14–16).",[3765,11442,11443,11446],{},[3747,11444,11445],{},"Локальна база SQLite"," для offline-зберігання поїздок (стаття 19).",[10940,11448,11450],{"id":11449},"додаємо-в-цій-статті","Додаємо в цій статті",[3762,11452,11453,11468,11490,11515,11525,11534],{},[3765,11454,11455,11461,11462,3819,11465,3823],{},[3747,11456,11457,3819,11459],{},[3780,11458,3818],{},[3780,11460,3822],{}," у типі ",[3780,11463,11464],{},"Trip",[3780,11466,11467],{},"Place",[3765,11469,11470,11475,11476,3783,11478,3783,11480,3783,11482,3783,11484,3783,11486,3783,11488,3823],{},[3747,11471,11472,11473],{},"Таблиця ",[3780,11474,4157],{}," у SQLite з полями ",[3780,11477,5166],{},[3780,11479,6267],{},[3780,11481,6245],{},[3780,11483,6309],{},[3780,11485,4221],{},[3780,11487,4189],{},[3780,11489,4193],{},[3765,11491,11492,11497,11498],{},[3747,11493,11494,11496],{},[3780,11495,5091],{}," hook"," — фоновий процес, який:\n",[3762,11499,11500,11503,11506,11509],{},[3765,11501,11502],{},"Слухає зміни мережі через NetInfo.",[3765,11504,11505],{},"Кожні 10 секунд перевіряє outbox.",[3765,11507,11508],{},"Для кожної pending-операції робить POST\u002FPATCH на API.",[3765,11510,11511,11512,11514],{},"Оновлює ",[3780,11513,3818],{}," у локальній базі.",[3765,11516,11517,11520,11521,11524],{},[3747,11518,11519],{},"Offline-banner"," у ",[3780,11522,11523],{},"app\u002F(tabs)\u002Findex.tsx"," (список поїздок).",[3765,11526,11527,11530,11531,4471],{},[3747,11528,11529],{},"Sync-badge"," на картці поїздки (",[3780,11532,11533],{},"TripCard.tsx",[3765,11535,11536,11539,11540,3823],{},[3747,11537,11538],{},"Retry-кнопка"," в деталях поїздки для записів із ",[3780,11541,4360],{},[3836,11543],{},[3843,11545,11547],{"id":11546},"повний-знімок-проєкту","Повний знімок проєкту",[3743,11549,11550,11551,11554],{},"Нижче — ",[3747,11552,11553],{},"вся структура Nomad"," на момент цієї статті з повним кодом у кожному файлі.",[7438,11556,11558,11565,11856,11998,12247,13540,14190,14392,15704,16053,16059,16062,16068,16663,18028,19032,19035,19037,19132,19134,19138,19141,19248,19250,19254,19373,19385,19387,19391,19395,19462,19464,19468,19535,19537,19541,19659,19661,19665,19668,19709,19718,19739,19746,19759,19761,19765],{"name":11557},"nomad-offline-sync",[3973,11559,11563],{"className":11560,"code":11561,"filename":11562,"language":6479,"meta":3978},[7444],"nomad\u002F\n├── app\u002F\n│   ├── (auth)\u002F\n│   │   └── login.tsx\n│   ├── (tabs)\u002F\n│   │   ├── trips\u002F\n│   │   │   ├── [id].tsx         # Деталі поїздки + retry button\n│   │   │   ├── index.tsx        # Список поїздок + offline banner\n│   │   │   └── _layout.tsx\n│   │   ├── _layout.tsx\n│   │   └── profile.tsx\n│   ├── create-trip.tsx          # Форма створення (modal)\n│   └── _layout.tsx              # Ініціалізація SQLite\n├── src\u002F\n│   ├── components\u002F\n│   │   └── OfflineBanner.tsx    # новий компонент\n│   ├── features\u002F\n│   │   ├── auth\u002F\n│   │   │   └── ...\n│   │   └── trips\u002F\n│   │       ├── model\u002F\n│   │       │   └── types.ts\n│   │       └── ui\u002F\n│   │           └── TripCard.tsx  # + sync badge\n│   ├── shared\u002F\n│   │   ├── db\u002F                   # новий модуль\n│   │   │   ├── index.ts\n│   │   │   ├── schema.ts         # trips + outbox tables\n│   │   │   ├── trips.ts          # CRUD + syncStatus\n│   │   │   └── outbox.ts         # черга операцій\n│   │   ├── types\u002F                # новий модуль\n│   │   │   └── index.ts          # SyncStatus, OutboxItem\n│   │   ├── theme\u002F\n│   │   └── ui\u002F\n│   ├── hooks\u002F\n│   │   ├── useNetworkStatus.ts   # новий\n│   │   ├── useSyncWorker.ts      # новий\n│   │   └── useTheme.ts\n│   ├── services\u002F\n│   │   └── tripsApi.ts           # RTK Query\n│   └── store\u002F\n│       └── index.ts              # RTK store\n├── package.json\n└── tsconfig.json\n","Структура",[3780,11564,11561],{"__ignoreMap":3978},[3973,11566,11568],{"className":6931,"code":11567,"filename":10927,"language":6933,"meta":3978,"style":3978},"{\n  \"name\": \"nomad\",\n  \"version\": \"1.0.0\",\n  \"main\": \"expo-router\u002Fentry\",\n  \"scripts\": {\n    \"start\": \"expo start\",\n    \"android\": \"expo start --android\",\n    \"ios\": \"expo start --ios\",\n    \"lint\": \"eslint .\",\n    \"type-check\": \"tsc --noEmit\"\n  },\n  \"dependencies\": {\n    \"expo\": \"~52.0.0\",\n    \"expo-router\": \"~4.0.0\",\n    \"expo-sqlite\": \"~15.0.0\",\n    \"react\": \"18.3.1\",\n    \"react-native\": \"0.76.5\",\n    \"@reduxjs\u002Ftoolkit\": \"^2.0.0\",\n    \"react-redux\": \"^9.0.0\",\n    \"react-hook-form\": \"^7.48.0\",\n    \"zod\": \"^3.22.0\",\n    \"@react-native-community\u002Fnetinfo\": \"^11.4.0\"\n  },\n  \"devDependencies\": {\n    \"@types\u002Freact\": \"~18.3.0\",\n    \"typescript\": \"~5.3.0\",\n    \"eslint\": \"^8.55.0\"\n  }\n}\n",[3780,11569,11570,11574,11586,11598,11609,11616,11628,11640,11652,11664,11674,11678,11685,11697,11709,11721,11733,11745,11757,11769,11781,11793,11803,11807,11814,11826,11838,11848,11852],{"__ignoreMap":3978},[3982,11571,11572],{"class":3984,"line":3985},[3982,11573,6765],{"class":3996},[3982,11575,11576,11579,11581,11584],{"class":3984,"line":4000},[3982,11577,11578],{"class":6770},"  \"name\"",[3982,11580,4007],{"class":3996},[3982,11582,11583],{"class":4028},"\"nomad\"",[3982,11585,6287],{"class":3996},[3982,11587,11588,11591,11593,11596],{"class":3984,"line":4020},[3982,11589,11590],{"class":6770},"  \"version\"",[3982,11592,4007],{"class":3996},[3982,11594,11595],{"class":4028},"\"1.0.0\"",[3982,11597,6287],{"class":3996},[3982,11599,11600,11602,11604,11607],{"class":3984,"line":4046},[3982,11601,11080],{"class":6770},[3982,11603,4007],{"class":3996},[3982,11605,11606],{"class":4028},"\"expo-router\u002Fentry\"",[3982,11608,6287],{"class":3996},[3982,11610,11611,11614],{"class":3984,"line":4069},[3982,11612,11613],{"class":6770},"  \"scripts\"",[3982,11615,11040],{"class":3996},[3982,11617,11618,11621,11623,11626],{"class":3984,"line":4086},[3982,11619,11620],{"class":6770},"    \"start\"",[3982,11622,4007],{"class":3996},[3982,11624,11625],{"class":4028},"\"expo start\"",[3982,11627,6287],{"class":3996},[3982,11629,11630,11633,11635,11638],{"class":3984,"line":4103},[3982,11631,11632],{"class":6770},"    \"android\"",[3982,11634,4007],{"class":3996},[3982,11636,11637],{"class":4028},"\"expo start --android\"",[3982,11639,6287],{"class":3996},[3982,11641,11642,11645,11647,11650],{"class":3984,"line":4119},[3982,11643,11644],{"class":6770},"    \"ios\"",[3982,11646,4007],{"class":3996},[3982,11648,11649],{"class":4028},"\"expo start --ios\"",[3982,11651,6287],{"class":3996},[3982,11653,11654,11657,11659,11662],{"class":3984,"line":4135},[3982,11655,11656],{"class":6770},"    \"lint\"",[3982,11658,4007],{"class":3996},[3982,11660,11661],{"class":4028},"\"eslint .\"",[3982,11663,6287],{"class":3996},[3982,11665,11666,11669,11671],{"class":3984,"line":4859},[3982,11667,11668],{"class":6770},"    \"type-check\"",[3982,11670,4007],{"class":3996},[3982,11672,11673],{"class":4028},"\"tsc --noEmit\"\n",[3982,11675,11676],{"class":3984,"line":4865},[3982,11677,8502],{"class":3996},[3982,11679,11680,11683],{"class":3984,"line":4871},[3982,11681,11682],{"class":6770},"  \"dependencies\"",[3982,11684,11040],{"class":3996},[3982,11686,11687,11690,11692,11695],{"class":3984,"line":4877},[3982,11688,11689],{"class":6770},"    \"expo\"",[3982,11691,4007],{"class":3996},[3982,11693,11694],{"class":4028},"\"~52.0.0\"",[3982,11696,6287],{"class":3996},[3982,11698,11699,11702,11704,11707],{"class":3984,"line":4883},[3982,11700,11701],{"class":6770},"    \"expo-router\"",[3982,11703,4007],{"class":3996},[3982,11705,11706],{"class":4028},"\"~4.0.0\"",[3982,11708,6287],{"class":3996},[3982,11710,11711,11714,11716,11719],{"class":3984,"line":4888},[3982,11712,11713],{"class":6770},"    \"expo-sqlite\"",[3982,11715,4007],{"class":3996},[3982,11717,11718],{"class":4028},"\"~15.0.0\"",[3982,11720,6287],{"class":3996},[3982,11722,11723,11726,11728,11731],{"class":3984,"line":4893},[3982,11724,11725],{"class":6770},"    \"react\"",[3982,11727,4007],{"class":3996},[3982,11729,11730],{"class":4028},"\"18.3.1\"",[3982,11732,6287],{"class":3996},[3982,11734,11735,11738,11740,11743],{"class":3984,"line":4899},[3982,11736,11737],{"class":6770},"    \"react-native\"",[3982,11739,4007],{"class":3996},[3982,11741,11742],{"class":4028},"\"0.76.5\"",[3982,11744,6287],{"class":3996},[3982,11746,11747,11750,11752,11755],{"class":3984,"line":4905},[3982,11748,11749],{"class":6770},"    \"@reduxjs\u002Ftoolkit\"",[3982,11751,4007],{"class":3996},[3982,11753,11754],{"class":4028},"\"^2.0.0\"",[3982,11756,6287],{"class":3996},[3982,11758,11759,11762,11764,11767],{"class":3984,"line":4911},[3982,11760,11761],{"class":6770},"    \"react-redux\"",[3982,11763,4007],{"class":3996},[3982,11765,11766],{"class":4028},"\"^9.0.0\"",[3982,11768,6287],{"class":3996},[3982,11770,11771,11774,11776,11779],{"class":3984,"line":4916},[3982,11772,11773],{"class":6770},"    \"react-hook-form\"",[3982,11775,4007],{"class":3996},[3982,11777,11778],{"class":4028},"\"^7.48.0\"",[3982,11780,6287],{"class":3996},[3982,11782,11783,11786,11788,11791],{"class":3984,"line":4921},[3982,11784,11785],{"class":6770},"    \"zod\"",[3982,11787,4007],{"class":3996},[3982,11789,11790],{"class":4028},"\"^3.22.0\"",[3982,11792,6287],{"class":3996},[3982,11794,11795,11798,11800],{"class":3984,"line":4927},[3982,11796,11797],{"class":6770},"    \"@react-native-community\u002Fnetinfo\"",[3982,11799,4007],{"class":3996},[3982,11801,11802],{"class":4028},"\"^11.4.0\"\n",[3982,11804,11805],{"class":3984,"line":4933},[3982,11806,8502],{"class":3996},[3982,11808,11809,11812],{"class":3984,"line":4938},[3982,11810,11811],{"class":6770},"  \"devDependencies\"",[3982,11813,11040],{"class":3996},[3982,11815,11816,11819,11821,11824],{"class":3984,"line":4943},[3982,11817,11818],{"class":6770},"    \"@types\u002Freact\"",[3982,11820,4007],{"class":3996},[3982,11822,11823],{"class":4028},"\"~18.3.0\"",[3982,11825,6287],{"class":3996},[3982,11827,11828,11831,11833,11836],{"class":3984,"line":4949},[3982,11829,11830],{"class":6770},"    \"typescript\"",[3982,11832,4007],{"class":3996},[3982,11834,11835],{"class":4028},"\"~5.3.0\"",[3982,11837,6287],{"class":3996},[3982,11839,11840,11843,11845],{"class":3984,"line":4954},[3982,11841,11842],{"class":6770},"    \"eslint\"",[3982,11844,4007],{"class":3996},[3982,11846,11847],{"class":4028},"\"^8.55.0\"\n",[3982,11849,11850],{"class":3984,"line":4960},[3982,11851,5417],{"class":3996},[3982,11853,11854],{"class":3984,"line":4966},[3982,11855,4852],{"class":3996},[3973,11857,11860],{"className":3975,"code":11858,"filename":11859,"language":3977,"meta":3978,"style":3978},"export type SyncStatus = 'pending' | 'syncing' | 'synced' | 'error';\n\nexport type OutboxItem = {\n  id: string;\n  operation: 'CREATE' | 'UPDATE' | 'DELETE';\n  resource: 'trip' | 'place';\n  payload: Record\u003Cstring, unknown>;\n  createdAt: number;\n  retryCount: number;\n  lastError?: string;\n};\n","src\u002Fshared\u002Ftypes\u002Findex.ts",[3780,11861,11862,11888,11892,11902,11912,11930,11944,11964,11974,11984,11994],{"__ignoreMap":3978},[3982,11863,11864,11866,11868,11870,11872,11874,11876,11878,11880,11882,11884,11886],{"class":3984,"line":3985},[3982,11865,5484],{"class":5210},[3982,11867,9171],{"class":3988},[3982,11869,4254],{"class":3992},[3982,11871,5243],{"class":3996},[3982,11873,4265],{"class":4028},[3982,11875,4032],{"class":3996},[3982,11877,4275],{"class":4028},[3982,11879,4032],{"class":3996},[3982,11881,4285],{"class":4028},[3982,11883,4032],{"class":3996},[3982,11885,4295],{"class":4028},[3982,11887,4043],{"class":3996},[3982,11889,11890],{"class":3984,"line":4000},[3982,11891,4832],{"emptyLinePlaceholder":4831},[3982,11893,11894,11896,11898,11900],{"class":3984,"line":4020},[3982,11895,5484],{"class":5210},[3982,11897,9171],{"class":3988},[3982,11899,3993],{"class":3992},[3982,11901,3997],{"class":3996},[3982,11903,11904,11906,11908,11910],{"class":3984,"line":4046},[3982,11905,4004],{"class":4003},[3982,11907,4007],{"class":3996},[3982,11909,4010],{"class":3992},[3982,11911,4043],{"class":3996},[3982,11913,11914,11916,11918,11920,11922,11924,11926,11928],{"class":3984,"line":4069},[3982,11915,4023],{"class":4003},[3982,11917,4007],{"class":3996},[3982,11919,4029],{"class":4028},[3982,11921,4032],{"class":3996},[3982,11923,4035],{"class":4028},[3982,11925,4032],{"class":3996},[3982,11927,4040],{"class":4028},[3982,11929,4043],{"class":3996},[3982,11931,11932,11934,11936,11938,11940,11942],{"class":3984,"line":4086},[3982,11933,4049],{"class":4003},[3982,11935,4007],{"class":3996},[3982,11937,4054],{"class":4028},[3982,11939,4032],{"class":3996},[3982,11941,4059],{"class":4028},[3982,11943,4043],{"class":3996},[3982,11945,11946,11948,11950,11953,11955,11957,11959,11961],{"class":3984,"line":4103},[3982,11947,4072],{"class":4003},[3982,11949,4007],{"class":3996},[3982,11951,11952],{"class":3992},"Record",[3982,11954,9430],{"class":3996},[3982,11956,4010],{"class":3992},[3982,11958,3783],{"class":3996},[3982,11960,4077],{"class":3992},[3982,11962,11963],{"class":3996},">;\n",[3982,11965,11966,11968,11970,11972],{"class":3984,"line":4119},[3982,11967,4089],{"class":4003},[3982,11969,4007],{"class":3996},[3982,11971,4094],{"class":3992},[3982,11973,4043],{"class":3996},[3982,11975,11976,11978,11980,11982],{"class":3984,"line":4135},[3982,11977,4106],{"class":4003},[3982,11979,4007],{"class":3996},[3982,11981,4094],{"class":3992},[3982,11983,4043],{"class":3996},[3982,11985,11986,11988,11990,11992],{"class":3984,"line":4859},[3982,11987,4122],{"class":4003},[3982,11989,4125],{"class":3996},[3982,11991,4010],{"class":3992},[3982,11993,4043],{"class":3996},[3982,11995,11996],{"class":3984,"line":4865},[3982,11997,4138],{"class":3996},[3973,11999,12002],{"className":3975,"code":12000,"filename":12001,"language":3977,"meta":3978,"style":3978},"import * as SQLite from 'expo-sqlite';\n\nexport async function initDatabase() {\n  const db = await SQLite.openDatabaseAsync('nomad.db');\n\n  await db.execAsync(`\n    CREATE TABLE IF NOT EXISTS trips (\n      id TEXT PRIMARY KEY,\n      title TEXT NOT NULL,\n      dateLabel TEXT NOT NULL,\n      description TEXT,\n      coverUri TEXT,\n      region TEXT,\n      isPrivate INTEGER DEFAULT 0,\n      plannedDays INTEGER,\n      hasItinerary INTEGER DEFAULT 0,\n      syncStatus TEXT DEFAULT 'pending',\n      syncError TEXT,\n      serverId TEXT,\n      createdAt INTEGER NOT NULL,\n      updatedAt INTEGER NOT NULL\n    );\n\n    CREATE TABLE IF NOT EXISTS outbox (\n      id TEXT PRIMARY KEY,\n      operation TEXT NOT NULL,\n      resource TEXT NOT NULL,\n      payload TEXT NOT NULL,\n      createdAt INTEGER NOT NULL,\n      retryCount INTEGER DEFAULT 0,\n      lastError TEXT\n    );\n\n    CREATE INDEX IF NOT EXISTS idx_outbox_created ON outbox(createdAt);\n    CREATE INDEX IF NOT EXISTS idx_trips_sync ON trips(syncStatus);\n  `);\n\n  return db;\n}\n","src\u002Fshared\u002Fdb\u002Fschema.ts",[3780,12003,12004,12023,12027,12041,12065,12069,12085,12090,12095,12100,12105,12110,12115,12120,12125,12130,12135,12140,12145,12150,12155,12160,12164,12168,12173,12177,12182,12187,12192,12196,12201,12206,12210,12214,12219,12224,12231,12235,12243],{"__ignoreMap":3978},[3982,12005,12006,12008,12011,12013,12016,12018,12021],{"class":3984,"line":3985},[3982,12007,5211],{"class":5210},[3982,12009,12010],{"class":3988}," *",[3982,12012,9981],{"class":5210},[3982,12014,12015],{"class":4003}," SQLite",[3982,12017,5217],{"class":5210},[3982,12019,12020],{"class":4028}," 'expo-sqlite'",[3982,12022,4043],{"class":3996},[3982,12024,12025],{"class":3984,"line":4000},[3982,12026,4832],{"emptyLinePlaceholder":4831},[3982,12028,12029,12031,12034,12036,12039],{"class":3984,"line":4020},[3982,12030,5484],{"class":5210},[3982,12032,12033],{"class":3988}," async",[3982,12035,5487],{"class":3988},[3982,12037,12038],{"class":5253}," initDatabase",[3982,12040,5493],{"class":3996},[3982,12042,12043,12045,12047,12049,12051,12053,12055,12058,12060,12063],{"class":3984,"line":4046},[3982,12044,5498],{"class":3988},[3982,12046,6349],{"class":5239},[3982,12048,5243],{"class":3996},[3982,12050,5246],{"class":5210},[3982,12052,12015],{"class":4003},[3982,12054,3823],{"class":3996},[3982,12056,12057],{"class":5253},"openDatabaseAsync",[3982,12059,5270],{"class":3996},[3982,12061,12062],{"class":4028},"'nomad.db'",[3982,12064,5375],{"class":3996},[3982,12066,12067],{"class":3984,"line":4069},[3982,12068,4832],{"emptyLinePlaceholder":4831},[3982,12070,12071,12073,12075,12077,12080,12082],{"class":3984,"line":4086},[3982,12072,6177],{"class":5210},[3982,12074,6349],{"class":4003},[3982,12076,3823],{"class":3996},[3982,12078,12079],{"class":5253},"execAsync",[3982,12081,5270],{"class":3996},[3982,12083,12084],{"class":4028},"`\n",[3982,12086,12087],{"class":3984,"line":4103},[3982,12088,12089],{"class":4028},"    CREATE TABLE IF NOT EXISTS trips (\n",[3982,12091,12092],{"class":3984,"line":4119},[3982,12093,12094],{"class":4028},"      id TEXT PRIMARY KEY,\n",[3982,12096,12097],{"class":3984,"line":4135},[3982,12098,12099],{"class":4028},"      title TEXT NOT NULL,\n",[3982,12101,12102],{"class":3984,"line":4859},[3982,12103,12104],{"class":4028},"      dateLabel TEXT NOT NULL,\n",[3982,12106,12107],{"class":3984,"line":4865},[3982,12108,12109],{"class":4028},"      description TEXT,\n",[3982,12111,12112],{"class":3984,"line":4871},[3982,12113,12114],{"class":4028},"      coverUri TEXT,\n",[3982,12116,12117],{"class":3984,"line":4877},[3982,12118,12119],{"class":4028},"      region TEXT,\n",[3982,12121,12122],{"class":3984,"line":4883},[3982,12123,12124],{"class":4028},"      isPrivate INTEGER DEFAULT 0,\n",[3982,12126,12127],{"class":3984,"line":4888},[3982,12128,12129],{"class":4028},"      plannedDays INTEGER,\n",[3982,12131,12132],{"class":3984,"line":4893},[3982,12133,12134],{"class":4028},"      hasItinerary INTEGER DEFAULT 0,\n",[3982,12136,12137],{"class":3984,"line":4899},[3982,12138,12139],{"class":4028},"      syncStatus TEXT DEFAULT 'pending',\n",[3982,12141,12142],{"class":3984,"line":4905},[3982,12143,12144],{"class":4028},"      syncError TEXT,\n",[3982,12146,12147],{"class":3984,"line":4911},[3982,12148,12149],{"class":4028},"      serverId TEXT,\n",[3982,12151,12152],{"class":3984,"line":4916},[3982,12153,12154],{"class":4028},"      createdAt INTEGER NOT NULL,\n",[3982,12156,12157],{"class":3984,"line":4921},[3982,12158,12159],{"class":4028},"      updatedAt INTEGER NOT NULL\n",[3982,12161,12162],{"class":3984,"line":4927},[3982,12163,9868],{"class":4028},[3982,12165,12166],{"class":3984,"line":4933},[3982,12167,4832],{"emptyLinePlaceholder":4831},[3982,12169,12170],{"class":3984,"line":4938},[3982,12171,12172],{"class":4028},"    CREATE TABLE IF NOT EXISTS outbox (\n",[3982,12174,12175],{"class":3984,"line":4943},[3982,12176,12094],{"class":4028},[3982,12178,12179],{"class":3984,"line":4949},[3982,12180,12181],{"class":4028},"      operation TEXT NOT NULL,\n",[3982,12183,12184],{"class":3984,"line":4954},[3982,12185,12186],{"class":4028},"      resource TEXT NOT NULL,\n",[3982,12188,12189],{"class":3984,"line":4960},[3982,12190,12191],{"class":4028},"      payload TEXT NOT NULL,\n",[3982,12193,12194],{"class":3984,"line":4966},[3982,12195,12154],{"class":4028},[3982,12197,12198],{"class":3984,"line":4972},[3982,12199,12200],{"class":4028},"      retryCount INTEGER DEFAULT 0,\n",[3982,12202,12203],{"class":3984,"line":4978},[3982,12204,12205],{"class":4028},"      lastError TEXT\n",[3982,12207,12208],{"class":3984,"line":4983},[3982,12209,9868],{"class":4028},[3982,12211,12212],{"class":3984,"line":4989},[3982,12213,4832],{"emptyLinePlaceholder":4831},[3982,12215,12216],{"class":3984,"line":4995},[3982,12217,12218],{"class":4028},"    CREATE INDEX IF NOT EXISTS idx_outbox_created ON outbox(createdAt);\n",[3982,12220,12221],{"class":3984,"line":5001},[3982,12222,12223],{"class":4028},"    CREATE INDEX IF NOT EXISTS idx_trips_sync ON trips(syncStatus);\n",[3982,12225,12226,12229],{"class":3984,"line":5007},[3982,12227,12228],{"class":4028},"  `",[3982,12230,5375],{"class":3996},[3982,12232,12233],{"class":3984,"line":5013},[3982,12234,4832],{"emptyLinePlaceholder":4831},[3982,12236,12237,12239,12241],{"class":3984,"line":5018},[3982,12238,5667],{"class":5210},[3982,12240,6349],{"class":4003},[3982,12242,4043],{"class":3996},[3982,12244,12245],{"class":3984,"line":5024},[3982,12246,4852],{"class":3996},[3973,12248,12251],{"className":3975,"code":12249,"filename":12250,"language":3977,"meta":3978,"style":3978},"import * as SQLite from 'expo-sqlite';\nimport type { Trip } from '@\u002Ffeatures\u002Ftrips\u002Fmodel\u002Ftypes';\nimport type { SyncStatus } from '@\u002Fshared\u002Ftypes';\n\nconst db = SQLite.openDatabaseSync('nomad.db');\n\nexport const tripsDb = {\n  async getAll(): Promise\u003C(Trip & { syncStatus: SyncStatus; syncError?: string; serverId?: string })[]> {\n    const rows = await db.getAllAsync\u003Cany>('SELECT * FROM trips ORDER BY createdAt DESC');\n    return rows.map(row => ({\n      id: row.id,\n      title: row.title,\n      dateLabel: row.dateLabel,\n      description: row.description || '',\n      coverUri: row.coverUri || '',\n      region: row.region || 'Інше',\n      isPrivate: Boolean(row.isPrivate),\n      plannedDays: row.plannedDays,\n      hasItinerary: Boolean(row.hasItinerary),\n      syncStatus: row.syncStatus as SyncStatus,\n      syncError: row.syncError,\n      serverId: row.serverId,\n    }));\n  },\n\n  async getById(id: string): Promise\u003C(Trip & { syncStatus: SyncStatus; syncError?: string; serverId?: string }) | null> {\n    const row = await db.getFirstAsync\u003Cany>('SELECT * FROM trips WHERE id = ?', [id]);\n    if (!row) return null;\n    \n    return {\n      id: row.id,\n      title: row.title,\n      dateLabel: row.dateLabel,\n      description: row.description || '',\n      coverUri: row.coverUri || '',\n      region: row.region || 'Інше',\n      isPrivate: Boolean(row.isPrivate),\n      plannedDays: row.plannedDays,\n      hasItinerary: Boolean(row.hasItinerary),\n      syncStatus: row.syncStatus as SyncStatus,\n      syncError: row.syncError,\n      serverId: row.serverId,\n    };\n  },\n\n  async create(trip: Omit\u003CTrip, 'id'>): Promise\u003CTrip & { syncStatus: SyncStatus }> {\n    const id = `local-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;\n    const now = Date.now();\n\n    await db.runAsync(\n      `INSERT INTO trips (\n        id, title, dateLabel, description, coverUri, region,\n        isPrivate, plannedDays, hasItinerary,\n        syncStatus, createdAt, updatedAt\n      ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n      [\n        id,\n        trip.title,\n        trip.dateLabel,\n        trip.description || null,\n        trip.coverUri || null,\n        trip.region,\n        trip.isPrivate ? 1 : 0,\n        trip.plannedDays || null,\n        trip.hasItinerary ? 1 : 0,\n        'pending',\n        now,\n        now,\n      ]\n    );\n\n    return { \n      ...trip, \n      id, \n      syncStatus: 'pending',\n      description: trip.description || '',\n      coverUri: trip.coverUri || '',\n    };\n  },\n\n  async updateSyncStatus(\n    id: string,\n    status: SyncStatus,\n    serverId?: string,\n    error?: string\n  ): Promise\u003Cvoid> {\n    const now = Date.now();\n    await db.runAsync(\n      `UPDATE trips SET syncStatus = ?, syncError = ?, serverId = ?, updatedAt = ? WHERE id = ?`,\n      [status, error || null, serverId || null, now, id]\n    );\n  },\n\n  async delete(id: string): Promise\u003Cvoid> {\n    await db.runAsync('DELETE FROM trips WHERE id = ?', [id]);\n  },\n};\n","src\u002Fshared\u002Fdb\u002Ftrips.ts",[3780,12252,12253,12269,12288,12307,12311,12333,12337,12348,12393,12423,12442,12455,12468,12482,12500,12518,12537,12556,12570,12588,12604,12617,12630,12635,12639,12643,12698,12731,12748,12753,12759,12771,12783,12795,12811,12827,12843,12859,12871,12887,12903,12915,12927,12931,12935,12939,12985,13047,13064,13068,13081,13086,13091,13096,13101,13108,13113,13120,13131,13141,13155,13169,13179,13198,13212,13230,13237,13244,13250,13255,13259,13263,13270,13280,13287,13295,13312,13328,13332,13336,13340,13349,13360,13371,13382,13392,13405,13421,13433,13440,13474,13478,13482,13486,13511,13532,13536],{"__ignoreMap":3978},[3982,12254,12255,12257,12259,12261,12263,12265,12267],{"class":3984,"line":3985},[3982,12256,5211],{"class":5210},[3982,12258,12010],{"class":3988},[3982,12260,9981],{"class":5210},[3982,12262,12015],{"class":4003},[3982,12264,5217],{"class":5210},[3982,12266,12020],{"class":4028},[3982,12268,4043],{"class":3996},[3982,12270,12271,12273,12275,12277,12279,12281,12283,12286],{"class":3984,"line":4000},[3982,12272,5211],{"class":5210},[3982,12274,9171],{"class":5210},[3982,12276,5444],{"class":3996},[3982,12278,11464],{"class":4003},[3982,12280,5455],{"class":3996},[3982,12282,5458],{"class":5210},[3982,12284,12285],{"class":4028}," '@\u002Ffeatures\u002Ftrips\u002Fmodel\u002Ftypes'",[3982,12287,4043],{"class":3996},[3982,12289,12290,12292,12294,12296,12298,12300,12302,12305],{"class":3984,"line":4020},[3982,12291,5211],{"class":5210},[3982,12293,9171],{"class":5210},[3982,12295,5444],{"class":3996},[3982,12297,9237],{"class":4003},[3982,12299,5455],{"class":3996},[3982,12301,5458],{"class":5210},[3982,12303,12304],{"class":4028}," '@\u002Fshared\u002Ftypes'",[3982,12306,4043],{"class":3996},[3982,12308,12309],{"class":3984,"line":4046},[3982,12310,4832],{"emptyLinePlaceholder":4831},[3982,12312,12313,12315,12317,12319,12322,12324,12327,12329,12331],{"class":3984,"line":4069},[3982,12314,5236],{"class":3988},[3982,12316,6349],{"class":5239},[3982,12318,5243],{"class":3996},[3982,12320,12321],{"class":4003},"SQLite",[3982,12323,3823],{"class":3996},[3982,12325,12326],{"class":5253},"openDatabaseSync",[3982,12328,5270],{"class":3996},[3982,12330,12062],{"class":4028},[3982,12332,5375],{"class":3996},[3982,12334,12335],{"class":3984,"line":4086},[3982,12336,4832],{"emptyLinePlaceholder":4831},[3982,12338,12339,12341,12343,12346],{"class":3984,"line":4103},[3982,12340,5484],{"class":5210},[3982,12342,9420],{"class":3988},[3982,12344,12345],{"class":5239}," tripsDb",[3982,12347,3997],{"class":3996},[3982,12349,12350,12352,12355,12358,12360,12363,12365,12368,12370,12372,12374,12376,12378,12380,12382,12384,12386,12388,12390],{"class":3984,"line":4119},[3982,12351,10495],{"class":3988},[3982,12353,12354],{"class":5253}," getAll",[3982,12356,12357],{"class":3996},"(): ",[3982,12359,10791],{"class":3992},[3982,12361,12362],{"class":3996},"\u003C(",[3982,12364,11464],{"class":3992},[3982,12366,12367],{"class":3996}," & { ",[3982,12369,3818],{"class":4003},[3982,12371,4007],{"class":3996},[3982,12373,9237],{"class":3992},[3982,12375,6096],{"class":3996},[3982,12377,3822],{"class":4003},[3982,12379,4125],{"class":3996},[3982,12381,4010],{"class":3992},[3982,12383,6096],{"class":3996},[3982,12385,4182],{"class":4003},[3982,12387,4125],{"class":3996},[3982,12389,4010],{"class":3992},[3982,12391,12392],{"class":3996}," })[]> {\n",[3982,12394,12395,12397,12400,12402,12404,12406,12408,12411,12413,12415,12418,12421],{"class":3984,"line":4135},[3982,12396,5598],{"class":3988},[3982,12398,12399],{"class":5239}," rows",[3982,12401,5243],{"class":3996},[3982,12403,5246],{"class":5210},[3982,12405,6349],{"class":4003},[3982,12407,3823],{"class":3996},[3982,12409,12410],{"class":5253},"getAllAsync",[3982,12412,9430],{"class":3996},[3982,12414,10785],{"class":3992},[3982,12416,12417],{"class":3996},">(",[3982,12419,12420],{"class":4028},"'SELECT * FROM trips ORDER BY createdAt DESC'",[3982,12422,5375],{"class":3996},[3982,12424,12425,12427,12429,12431,12433,12435,12438,12440],{"class":3984,"line":4859},[3982,12426,5649],{"class":5210},[3982,12428,12399],{"class":4003},[3982,12430,3823],{"class":3996},[3982,12432,9790],{"class":5253},[3982,12434,5270],{"class":3996},[3982,12436,12437],{"class":4003},"row",[3982,12439,5339],{"class":3988},[3982,12441,9451],{"class":3996},[3982,12443,12444,12446,12449,12451,12453],{"class":3984,"line":4865},[3982,12445,9603],{"class":4003},[3982,12447,12448],{"class":4003}," row",[3982,12450,3823],{"class":3996},[3982,12452,5166],{"class":4003},[3982,12454,6287],{"class":3996},[3982,12456,12457,12460,12462,12464,12466],{"class":3984,"line":4871},[3982,12458,12459],{"class":4003},"      title:",[3982,12461,12448],{"class":4003},[3982,12463,3823],{"class":3996},[3982,12465,7924],{"class":4003},[3982,12467,6287],{"class":3996},[3982,12469,12470,12473,12475,12477,12480],{"class":3984,"line":4877},[3982,12471,12472],{"class":4003},"      dateLabel:",[3982,12474,12448],{"class":4003},[3982,12476,3823],{"class":3996},[3982,12478,12479],{"class":4003},"dateLabel",[3982,12481,6287],{"class":3996},[3982,12483,12484,12487,12489,12491,12494,12496,12498],{"class":3984,"line":4883},[3982,12485,12486],{"class":4003},"      description:",[3982,12488,12448],{"class":4003},[3982,12490,3823],{"class":3996},[3982,12492,12493],{"class":4003},"description",[3982,12495,9847],{"class":3996},[3982,12497,7678],{"class":4028},[3982,12499,6287],{"class":3996},[3982,12501,12502,12505,12507,12509,12512,12514,12516],{"class":3984,"line":4888},[3982,12503,12504],{"class":4003},"      coverUri:",[3982,12506,12448],{"class":4003},[3982,12508,3823],{"class":3996},[3982,12510,12511],{"class":4003},"coverUri",[3982,12513,9847],{"class":3996},[3982,12515,7678],{"class":4028},[3982,12517,6287],{"class":3996},[3982,12519,12520,12523,12525,12527,12530,12532,12535],{"class":3984,"line":4893},[3982,12521,12522],{"class":4003},"      region:",[3982,12524,12448],{"class":4003},[3982,12526,3823],{"class":3996},[3982,12528,12529],{"class":4003},"region",[3982,12531,9847],{"class":3996},[3982,12533,12534],{"class":4028},"'Інше'",[3982,12536,6287],{"class":3996},[3982,12538,12539,12542,12545,12547,12549,12551,12554],{"class":3984,"line":4899},[3982,12540,12541],{"class":4003},"      isPrivate:",[3982,12543,12544],{"class":5253}," Boolean",[3982,12546,5270],{"class":3996},[3982,12548,12437],{"class":4003},[3982,12550,3823],{"class":3996},[3982,12552,12553],{"class":4003},"isPrivate",[3982,12555,6021],{"class":3996},[3982,12557,12558,12561,12563,12565,12568],{"class":3984,"line":4905},[3982,12559,12560],{"class":4003},"      plannedDays:",[3982,12562,12448],{"class":4003},[3982,12564,3823],{"class":3996},[3982,12566,12567],{"class":4003},"plannedDays",[3982,12569,6287],{"class":3996},[3982,12571,12572,12575,12577,12579,12581,12583,12586],{"class":3984,"line":4911},[3982,12573,12574],{"class":4003},"      hasItinerary:",[3982,12576,12544],{"class":5253},[3982,12578,5270],{"class":3996},[3982,12580,12437],{"class":4003},[3982,12582,3823],{"class":3996},[3982,12584,12585],{"class":4003},"hasItinerary",[3982,12587,6021],{"class":3996},[3982,12589,12590,12592,12594,12596,12598,12600,12602],{"class":3984,"line":4916},[3982,12591,9637],{"class":4003},[3982,12593,12448],{"class":4003},[3982,12595,3823],{"class":3996},[3982,12597,3818],{"class":4003},[3982,12599,9981],{"class":5210},[3982,12601,4254],{"class":3992},[3982,12603,6287],{"class":3996},[3982,12605,12606,12609,12611,12613,12615],{"class":3984,"line":4921},[3982,12607,12608],{"class":4003},"      syncError:",[3982,12610,12448],{"class":4003},[3982,12612,3823],{"class":3996},[3982,12614,3822],{"class":4003},[3982,12616,6287],{"class":3996},[3982,12618,12619,12622,12624,12626,12628],{"class":3984,"line":4927},[3982,12620,12621],{"class":4003},"      serverId:",[3982,12623,12448],{"class":4003},[3982,12625,3823],{"class":3996},[3982,12627,4182],{"class":4003},[3982,12629,6287],{"class":3996},[3982,12631,12632],{"class":3984,"line":4933},[3982,12633,12634],{"class":3996},"    }));\n",[3982,12636,12637],{"class":3984,"line":4938},[3982,12638,8502],{"class":3996},[3982,12640,12641],{"class":3984,"line":4943},[3982,12642,4832],{"emptyLinePlaceholder":4831},[3982,12644,12645,12647,12650,12652,12654,12656,12658,12660,12662,12664,12666,12668,12670,12672,12674,12676,12678,12680,12682,12684,12686,12688,12690,12693,12696],{"class":3984,"line":4949},[3982,12646,10495],{"class":3988},[3982,12648,12649],{"class":5253}," getById",[3982,12651,5270],{"class":3996},[3982,12653,5166],{"class":4003},[3982,12655,4007],{"class":3996},[3982,12657,4010],{"class":3992},[3982,12659,10788],{"class":3996},[3982,12661,10791],{"class":3992},[3982,12663,12362],{"class":3996},[3982,12665,11464],{"class":3992},[3982,12667,12367],{"class":3996},[3982,12669,3818],{"class":4003},[3982,12671,4007],{"class":3996},[3982,12673,9237],{"class":3992},[3982,12675,6096],{"class":3996},[3982,12677,3822],{"class":4003},[3982,12679,4125],{"class":3996},[3982,12681,4010],{"class":3992},[3982,12683,6096],{"class":3996},[3982,12685,4182],{"class":4003},[3982,12687,4125],{"class":3996},[3982,12689,4010],{"class":3992},[3982,12691,12692],{"class":3996}," }) | ",[3982,12694,12695],{"class":3992},"null",[3982,12697,10799],{"class":3996},[3982,12699,12700,12702,12704,12706,12708,12710,12712,12715,12717,12719,12721,12724,12727,12729],{"class":3984,"line":4954},[3982,12701,5598],{"class":3988},[3982,12703,12448],{"class":5239},[3982,12705,5243],{"class":3996},[3982,12707,5246],{"class":5210},[3982,12709,6349],{"class":4003},[3982,12711,3823],{"class":3996},[3982,12713,12714],{"class":5253},"getFirstAsync",[3982,12716,9430],{"class":3996},[3982,12718,10785],{"class":3992},[3982,12720,12417],{"class":3996},[3982,12722,12723],{"class":4028},"'SELECT * FROM trips WHERE id = ?'",[3982,12725,12726],{"class":3996},", [",[3982,12728,5166],{"class":4003},[3982,12730,10486],{"class":3996},[3982,12732,12733,12735,12737,12739,12741,12743,12746],{"class":3984,"line":4960},[3982,12734,6324],{"class":5210},[3982,12736,10382],{"class":3996},[3982,12738,12437],{"class":4003},[3982,12740,9317],{"class":3996},[3982,12742,10389],{"class":5210},[3982,12744,12745],{"class":3988}," null",[3982,12747,4043],{"class":3996},[3982,12749,12750],{"class":3984,"line":4966},[3982,12751,12752],{"class":3996},"    \n",[3982,12754,12755,12757],{"class":3984,"line":4972},[3982,12756,5649],{"class":5210},[3982,12758,5342],{"class":3996},[3982,12760,12761,12763,12765,12767,12769],{"class":3984,"line":4978},[3982,12762,9603],{"class":4003},[3982,12764,12448],{"class":4003},[3982,12766,3823],{"class":3996},[3982,12768,5166],{"class":4003},[3982,12770,6287],{"class":3996},[3982,12772,12773,12775,12777,12779,12781],{"class":3984,"line":4983},[3982,12774,12459],{"class":4003},[3982,12776,12448],{"class":4003},[3982,12778,3823],{"class":3996},[3982,12780,7924],{"class":4003},[3982,12782,6287],{"class":3996},[3982,12784,12785,12787,12789,12791,12793],{"class":3984,"line":4989},[3982,12786,12472],{"class":4003},[3982,12788,12448],{"class":4003},[3982,12790,3823],{"class":3996},[3982,12792,12479],{"class":4003},[3982,12794,6287],{"class":3996},[3982,12796,12797,12799,12801,12803,12805,12807,12809],{"class":3984,"line":4995},[3982,12798,12486],{"class":4003},[3982,12800,12448],{"class":4003},[3982,12802,3823],{"class":3996},[3982,12804,12493],{"class":4003},[3982,12806,9847],{"class":3996},[3982,12808,7678],{"class":4028},[3982,12810,6287],{"class":3996},[3982,12812,12813,12815,12817,12819,12821,12823,12825],{"class":3984,"line":5001},[3982,12814,12504],{"class":4003},[3982,12816,12448],{"class":4003},[3982,12818,3823],{"class":3996},[3982,12820,12511],{"class":4003},[3982,12822,9847],{"class":3996},[3982,12824,7678],{"class":4028},[3982,12826,6287],{"class":3996},[3982,12828,12829,12831,12833,12835,12837,12839,12841],{"class":3984,"line":5007},[3982,12830,12522],{"class":4003},[3982,12832,12448],{"class":4003},[3982,12834,3823],{"class":3996},[3982,12836,12529],{"class":4003},[3982,12838,9847],{"class":3996},[3982,12840,12534],{"class":4028},[3982,12842,6287],{"class":3996},[3982,12844,12845,12847,12849,12851,12853,12855,12857],{"class":3984,"line":5013},[3982,12846,12541],{"class":4003},[3982,12848,12544],{"class":5253},[3982,12850,5270],{"class":3996},[3982,12852,12437],{"class":4003},[3982,12854,3823],{"class":3996},[3982,12856,12553],{"class":4003},[3982,12858,6021],{"class":3996},[3982,12860,12861,12863,12865,12867,12869],{"class":3984,"line":5018},[3982,12862,12560],{"class":4003},[3982,12864,12448],{"class":4003},[3982,12866,3823],{"class":3996},[3982,12868,12567],{"class":4003},[3982,12870,6287],{"class":3996},[3982,12872,12873,12875,12877,12879,12881,12883,12885],{"class":3984,"line":5024},[3982,12874,12574],{"class":4003},[3982,12876,12544],{"class":5253},[3982,12878,5270],{"class":3996},[3982,12880,12437],{"class":4003},[3982,12882,3823],{"class":3996},[3982,12884,12585],{"class":4003},[3982,12886,6021],{"class":3996},[3982,12888,12889,12891,12893,12895,12897,12899,12901],{"class":3984,"line":5030},[3982,12890,9637],{"class":4003},[3982,12892,12448],{"class":4003},[3982,12894,3823],{"class":3996},[3982,12896,3818],{"class":4003},[3982,12898,9981],{"class":5210},[3982,12900,4254],{"class":3992},[3982,12902,6287],{"class":3996},[3982,12904,12905,12907,12909,12911,12913],{"class":3984,"line":5035},[3982,12906,12608],{"class":4003},[3982,12908,12448],{"class":4003},[3982,12910,3823],{"class":3996},[3982,12912,3822],{"class":4003},[3982,12914,6287],{"class":3996},[3982,12916,12917,12919,12921,12923,12925],{"class":3984,"line":8065},[3982,12918,12621],{"class":4003},[3982,12920,12448],{"class":4003},[3982,12922,3823],{"class":3996},[3982,12924,4182],{"class":4003},[3982,12926,6287],{"class":3996},[3982,12928,12929],{"class":3984,"line":8086},[3982,12930,9670],{"class":3996},[3982,12932,12933],{"class":3984,"line":8095},[3982,12934,8502],{"class":3996},[3982,12936,12937],{"class":3984,"line":8105},[3982,12938,4832],{"emptyLinePlaceholder":4831},[3982,12940,12941,12943,12946,12948,12951,12953,12956,12958,12960,12962,12965,12968,12970,12972,12974,12976,12978,12980,12982],{"class":3984,"line":8110},[3982,12942,10495],{"class":3988},[3982,12944,12945],{"class":5253}," create",[3982,12947,5270],{"class":3996},[3982,12949,12950],{"class":4003},"trip",[3982,12952,4007],{"class":3996},[3982,12954,12955],{"class":3992},"Omit",[3982,12957,9430],{"class":3996},[3982,12959,11464],{"class":3992},[3982,12961,3783],{"class":3996},[3982,12963,12964],{"class":4028},"'id'",[3982,12966,12967],{"class":3996},">): ",[3982,12969,10791],{"class":3992},[3982,12971,9430],{"class":3996},[3982,12973,11464],{"class":3992},[3982,12975,12367],{"class":3996},[3982,12977,3818],{"class":4003},[3982,12979,4007],{"class":3996},[3982,12981,9237],{"class":3992},[3982,12983,12984],{"class":3996}," }> {\n",[3982,12986,12987,12989,12992,12994,12997,12999,13001,13003,13005,13007,13009,13011,13013,13015,13017,13019,13021,13023,13025,13027,13029,13031,13033,13035,13037,13039,13041,13043,13045],{"class":3984,"line":8120},[3982,12988,5598],{"class":3988},[3982,12990,12991],{"class":5239}," id",[3982,12993,5243],{"class":3996},[3982,12995,12996],{"class":4028},"`local-",[3982,12998,6237],{"class":3988},[3982,13000,9611],{"class":4003},[3982,13002,3823],{"class":6242},[3982,13004,9616],{"class":5253},[3982,13006,9619],{"class":6242},[3982,13008,6248],{"class":3988},[3982,13010,5768],{"class":4028},[3982,13012,6237],{"class":3988},[3982,13014,5986],{"class":4003},[3982,13016,3823],{"class":6242},[3982,13018,6647],{"class":5253},[3982,13020,5555],{"class":6242},[3982,13022,10646],{"class":5253},[3982,13024,5270],{"class":6242},[3982,13026,10651],{"class":6014},[3982,13028,4471],{"class":6242},[3982,13030,10656],{"class":5253},[3982,13032,5270],{"class":6242},[3982,13034,5937],{"class":6014},[3982,13036,3783],{"class":6242},[3982,13038,10665],{"class":6014},[3982,13040,7431],{"class":6242},[3982,13042,6248],{"class":3988},[3982,13044,6251],{"class":4028},[3982,13046,4043],{"class":3996},[3982,13048,13049,13051,13054,13056,13058,13060,13062],{"class":3984,"line":8128},[3982,13050,5598],{"class":3988},[3982,13052,13053],{"class":5239}," now",[3982,13055,5243],{"class":3996},[3982,13057,9611],{"class":4003},[3982,13059,3823],{"class":3996},[3982,13061,9616],{"class":5253},[3982,13063,5257],{"class":3996},[3982,13065,13066],{"class":3984,"line":8140},[3982,13067,4832],{"emptyLinePlaceholder":4831},[3982,13069,13070,13072,13074,13076,13079],{"class":3984,"line":8153},[3982,13071,6515],{"class":5210},[3982,13073,6349],{"class":4003},[3982,13075,3823],{"class":3996},[3982,13077,13078],{"class":5253},"runAsync",[3982,13080,5994],{"class":3996},[3982,13082,13083],{"class":3984,"line":8167},[3982,13084,13085],{"class":4028},"      `INSERT INTO trips (\n",[3982,13087,13088],{"class":3984,"line":8183},[3982,13089,13090],{"class":4028},"        id, title, dateLabel, description, coverUri, region,\n",[3982,13092,13093],{"class":3984,"line":8208},[3982,13094,13095],{"class":4028},"        isPrivate, plannedDays, hasItinerary,\n",[3982,13097,13098],{"class":3984,"line":8223},[3982,13099,13100],{"class":4028},"        syncStatus, createdAt, updatedAt\n",[3982,13102,13103,13106],{"class":3984,"line":8241},[3982,13104,13105],{"class":4028},"      ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`",[3982,13107,6287],{"class":3996},[3982,13109,13110],{"class":3984,"line":8271},[3982,13111,13112],{"class":3996},"      [\n",[3982,13114,13115,13118],{"class":3984,"line":8277},[3982,13116,13117],{"class":4003},"        id",[3982,13119,6287],{"class":3996},[3982,13121,13122,13125,13127,13129],{"class":3984,"line":8294},[3982,13123,13124],{"class":4003},"        trip",[3982,13126,3823],{"class":3996},[3982,13128,7924],{"class":4003},[3982,13130,6287],{"class":3996},[3982,13132,13133,13135,13137,13139],{"class":3984,"line":8308},[3982,13134,13124],{"class":4003},[3982,13136,3823],{"class":3996},[3982,13138,12479],{"class":4003},[3982,13140,6287],{"class":3996},[3982,13142,13143,13145,13147,13149,13151,13153],{"class":3984,"line":8313},[3982,13144,13124],{"class":4003},[3982,13146,3823],{"class":3996},[3982,13148,12493],{"class":4003},[3982,13150,9847],{"class":3996},[3982,13152,12695],{"class":3988},[3982,13154,6287],{"class":3996},[3982,13156,13157,13159,13161,13163,13165,13167],{"class":3984,"line":8319},[3982,13158,13124],{"class":4003},[3982,13160,3823],{"class":3996},[3982,13162,12511],{"class":4003},[3982,13164,9847],{"class":3996},[3982,13166,12695],{"class":3988},[3982,13168,6287],{"class":3996},[3982,13170,13171,13173,13175,13177],{"class":3984,"line":8325},[3982,13172,13124],{"class":4003},[3982,13174,3823],{"class":3996},[3982,13176,12529],{"class":4003},[3982,13178,6287],{"class":3996},[3982,13180,13181,13183,13185,13187,13189,13191,13193,13196],{"class":3984,"line":8330},[3982,13182,13124],{"class":4003},[3982,13184,3823],{"class":3996},[3982,13186,12553],{"class":4003},[3982,13188,6275],{"class":3996},[3982,13190,5926],{"class":6014},[3982,13192,6281],{"class":3996},[3982,13194,13195],{"class":6014},"0",[3982,13197,6287],{"class":3996},[3982,13199,13200,13202,13204,13206,13208,13210],{"class":3984,"line":8336},[3982,13201,13124],{"class":4003},[3982,13203,3823],{"class":3996},[3982,13205,12567],{"class":4003},[3982,13207,9847],{"class":3996},[3982,13209,12695],{"class":3988},[3982,13211,6287],{"class":3996},[3982,13213,13214,13216,13218,13220,13222,13224,13226,13228],{"class":3984,"line":8342},[3982,13215,13124],{"class":4003},[3982,13217,3823],{"class":3996},[3982,13219,12585],{"class":4003},[3982,13221,6275],{"class":3996},[3982,13223,5926],{"class":6014},[3982,13225,6281],{"class":3996},[3982,13227,13195],{"class":6014},[3982,13229,6287],{"class":3996},[3982,13231,13232,13235],{"class":3984,"line":8348},[3982,13233,13234],{"class":4028},"        'pending'",[3982,13236,6287],{"class":3996},[3982,13238,13239,13242],{"class":3984,"line":8354},[3982,13240,13241],{"class":4003},"        now",[3982,13243,6287],{"class":3996},[3982,13245,13246,13248],{"class":3984,"line":8360},[3982,13247,13241],{"class":4003},[3982,13249,6287],{"class":3996},[3982,13251,13252],{"class":3984,"line":8366},[3982,13253,13254],{"class":3996},"      ]\n",[3982,13256,13257],{"class":3984,"line":8372},[3982,13258,9868],{"class":3996},[3982,13260,13261],{"class":3984,"line":8377},[3982,13262,4832],{"emptyLinePlaceholder":4831},[3982,13264,13265,13267],{"class":3984,"line":8383},[3982,13266,5649],{"class":5210},[3982,13268,13269],{"class":3996}," { \n",[3982,13271,13272,13275,13277],{"class":3984,"line":8389},[3982,13273,13274],{"class":3996},"      ...",[3982,13276,12950],{"class":4003},[3982,13278,13279],{"class":3996},", \n",[3982,13281,13282,13285],{"class":3984,"line":8395},[3982,13283,13284],{"class":4003},"      id",[3982,13286,13279],{"class":3996},[3982,13288,13289,13291,13293],{"class":3984,"line":8401},[3982,13290,9637],{"class":4003},[3982,13292,9640],{"class":4028},[3982,13294,6287],{"class":3996},[3982,13296,13297,13299,13302,13304,13306,13308,13310],{"class":3984,"line":8407},[3982,13298,12486],{"class":4003},[3982,13300,13301],{"class":4003}," trip",[3982,13303,3823],{"class":3996},[3982,13305,12493],{"class":4003},[3982,13307,9847],{"class":3996},[3982,13309,7678],{"class":4028},[3982,13311,6287],{"class":3996},[3982,13313,13314,13316,13318,13320,13322,13324,13326],{"class":3984,"line":8413},[3982,13315,12504],{"class":4003},[3982,13317,13301],{"class":4003},[3982,13319,3823],{"class":3996},[3982,13321,12511],{"class":4003},[3982,13323,9847],{"class":3996},[3982,13325,7678],{"class":4028},[3982,13327,6287],{"class":3996},[3982,13329,13330],{"class":3984,"line":8418},[3982,13331,9670],{"class":3996},[3982,13333,13334],{"class":3984,"line":8423},[3982,13335,8502],{"class":3996},[3982,13337,13338],{"class":3984,"line":8428},[3982,13339,4832],{"emptyLinePlaceholder":4831},[3982,13341,13342,13344,13347],{"class":3984,"line":8434},[3982,13343,10495],{"class":3988},[3982,13345,13346],{"class":5253}," updateSyncStatus",[3982,13348,5994],{"class":3996},[3982,13350,13351,13354,13356,13358],{"class":3984,"line":8458},[3982,13352,13353],{"class":4003},"    id",[3982,13355,4007],{"class":3996},[3982,13357,4010],{"class":3992},[3982,13359,6287],{"class":3996},[3982,13361,13362,13365,13367,13369],{"class":3984,"line":8466},[3982,13363,13364],{"class":4003},"    status",[3982,13366,4007],{"class":3996},[3982,13368,9237],{"class":3992},[3982,13370,6287],{"class":3996},[3982,13372,13373,13376,13378,13380],{"class":3984,"line":8477},[3982,13374,13375],{"class":4003},"    serverId",[3982,13377,4125],{"class":3996},[3982,13379,4010],{"class":3992},[3982,13381,6287],{"class":3996},[3982,13383,13384,13387,13389],{"class":3984,"line":8488},[3982,13385,13386],{"class":4003},"    error",[3982,13388,4125],{"class":3996},[3982,13390,13391],{"class":3992},"string\n",[3982,13393,13394,13397,13399,13401,13403],{"class":3984,"line":8499},[3982,13395,13396],{"class":3996},"  ): ",[3982,13398,10791],{"class":3992},[3982,13400,9430],{"class":3996},[3982,13402,10796],{"class":3992},[3982,13404,10799],{"class":3996},[3982,13406,13407,13409,13411,13413,13415,13417,13419],{"class":3984,"line":8505},[3982,13408,5598],{"class":3988},[3982,13410,13053],{"class":5239},[3982,13412,5243],{"class":3996},[3982,13414,9611],{"class":4003},[3982,13416,3823],{"class":3996},[3982,13418,9616],{"class":5253},[3982,13420,5257],{"class":3996},[3982,13422,13423,13425,13427,13429,13431],{"class":3984,"line":8529},[3982,13424,6515],{"class":5210},[3982,13426,6349],{"class":4003},[3982,13428,3823],{"class":3996},[3982,13430,13078],{"class":5253},[3982,13432,5994],{"class":3996},[3982,13434,13435,13438],{"class":3984,"line":8537},[3982,13436,13437],{"class":4028},"      `UPDATE trips SET syncStatus = ?, syncError = ?, serverId = ?, updatedAt = ? WHERE id = ?`",[3982,13439,6287],{"class":3996},[3982,13441,13442,13445,13447,13449,13451,13453,13455,13457,13459,13461,13463,13465,13467,13469,13471],{"class":3984,"line":8548},[3982,13443,13444],{"class":3996},"      [",[3982,13446,9342],{"class":4003},[3982,13448,3783],{"class":3996},[3982,13450,3789],{"class":4003},[3982,13452,9847],{"class":3996},[3982,13454,12695],{"class":3988},[3982,13456,3783],{"class":3996},[3982,13458,4182],{"class":4003},[3982,13460,9847],{"class":3996},[3982,13462,12695],{"class":3988},[3982,13464,3783],{"class":3996},[3982,13466,9616],{"class":4003},[3982,13468,3783],{"class":3996},[3982,13470,5166],{"class":4003},[3982,13472,13473],{"class":3996},"]\n",[3982,13475,13476],{"class":3984,"line":8559},[3982,13477,9868],{"class":3996},[3982,13479,13480],{"class":3984,"line":8569},[3982,13481,8502],{"class":3996},[3982,13483,13484],{"class":3984,"line":8574},[3982,13485,4832],{"emptyLinePlaceholder":4831},[3982,13487,13488,13490,13493,13495,13497,13499,13501,13503,13505,13507,13509],{"class":3984,"line":8582},[3982,13489,10495],{"class":3988},[3982,13491,13492],{"class":5253}," delete",[3982,13494,5270],{"class":3996},[3982,13496,5166],{"class":4003},[3982,13498,4007],{"class":3996},[3982,13500,4010],{"class":3992},[3982,13502,10788],{"class":3996},[3982,13504,10791],{"class":3992},[3982,13506,9430],{"class":3996},[3982,13508,10796],{"class":3992},[3982,13510,10799],{"class":3996},[3982,13512,13513,13515,13517,13519,13521,13523,13526,13528,13530],{"class":3984,"line":8593},[3982,13514,6515],{"class":5210},[3982,13516,6349],{"class":4003},[3982,13518,3823],{"class":3996},[3982,13520,13078],{"class":5253},[3982,13522,5270],{"class":3996},[3982,13524,13525],{"class":4028},"'DELETE FROM trips WHERE id = ?'",[3982,13527,12726],{"class":3996},[3982,13529,5166],{"class":4003},[3982,13531,10486],{"class":3996},[3982,13533,13534],{"class":3984,"line":8602},[3982,13535,8502],{"class":3996},[3982,13537,13538],{"class":3984,"line":8613},[3982,13539,4138],{"class":3996},[3973,13541,13544],{"className":3975,"code":13542,"filename":13543,"language":3977,"meta":3978,"style":3978},"import * as SQLite from 'expo-sqlite';\nimport type { OutboxItem } from '@\u002Fshared\u002Ftypes';\n\nconst db = SQLite.openDatabaseSync('nomad.db');\n\nexport const outboxDb = {\n  async getAll(): Promise\u003COutboxItem[]> {\n    const rows = await db.getAllAsync\u003C{\n      id: string;\n      operation: string;\n      resource: string;\n      payload: string;\n      createdAt: number;\n      retryCount: number;\n      lastError: string | null;\n    }>('SELECT * FROM outbox ORDER BY createdAt ASC');\n\n    return rows.map(row => ({\n      ...row,\n      operation: row.operation as 'CREATE' | 'UPDATE' | 'DELETE',\n      resource: row.resource as 'trip' | 'place',\n      payload: JSON.parse(row.payload),\n      lastError: row.lastError || undefined,\n    }));\n  },\n\n  async add(item: Omit\u003COutboxItem, 'id' | 'createdAt' | 'retryCount'>): Promise\u003Cvoid> {\n    const id = `outbox-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;\n    await db.runAsync(\n      'INSERT INTO outbox (id, operation, resource, payload, createdAt, retryCount) VALUES (?, ?, ?, ?, ?, ?)',\n      [id, item.operation, item.resource, JSON.stringify(item.payload), Date.now(), 0]\n    );\n  },\n\n  async updateRetry(id: string, error: string): Promise\u003Cvoid> {\n    await db.runAsync(\n      'UPDATE outbox SET retryCount = retryCount + 1, lastError = ? WHERE id = ?',\n      [error, id]\n    );\n  },\n\n  async delete(id: string): Promise\u003Cvoid> {\n    await db.runAsync('DELETE FROM outbox WHERE id = ?', [id]);\n  },\n};\n","src\u002Fshared\u002Fdb\u002Foutbox.ts",[3780,13545,13546,13562,13580,13584,13604,13608,13619,13636,13655,13665,13676,13687,13698,13709,13720,13735,13745,13749,13767,13775,13801,13823,13844,13860,13864,13868,13872,13915,13976,13988,13995,14049,14053,14057,14061,14094,14106,14113,14125,14129,14133,14137,14161,14182,14186],{"__ignoreMap":3978},[3982,13547,13548,13550,13552,13554,13556,13558,13560],{"class":3984,"line":3985},[3982,13549,5211],{"class":5210},[3982,13551,12010],{"class":3988},[3982,13553,9981],{"class":5210},[3982,13555,12015],{"class":4003},[3982,13557,5217],{"class":5210},[3982,13559,12020],{"class":4028},[3982,13561,4043],{"class":3996},[3982,13563,13564,13566,13568,13570,13572,13574,13576,13578],{"class":3984,"line":4000},[3982,13565,5211],{"class":5210},[3982,13567,9171],{"class":5210},[3982,13569,5444],{"class":3996},[3982,13571,6079],{"class":4003},[3982,13573,5455],{"class":3996},[3982,13575,5458],{"class":5210},[3982,13577,12304],{"class":4028},[3982,13579,4043],{"class":3996},[3982,13581,13582],{"class":3984,"line":4020},[3982,13583,4832],{"emptyLinePlaceholder":4831},[3982,13585,13586,13588,13590,13592,13594,13596,13598,13600,13602],{"class":3984,"line":4046},[3982,13587,5236],{"class":3988},[3982,13589,6349],{"class":5239},[3982,13591,5243],{"class":3996},[3982,13593,12321],{"class":4003},[3982,13595,3823],{"class":3996},[3982,13597,12326],{"class":5253},[3982,13599,5270],{"class":3996},[3982,13601,12062],{"class":4028},[3982,13603,5375],{"class":3996},[3982,13605,13606],{"class":3984,"line":4069},[3982,13607,4832],{"emptyLinePlaceholder":4831},[3982,13609,13610,13612,13614,13617],{"class":3984,"line":4086},[3982,13611,5484],{"class":5210},[3982,13613,9420],{"class":3988},[3982,13615,13616],{"class":5239}," outboxDb",[3982,13618,3997],{"class":3996},[3982,13620,13621,13623,13625,13627,13629,13631,13633],{"class":3984,"line":4103},[3982,13622,10495],{"class":3988},[3982,13624,12354],{"class":5253},[3982,13626,12357],{"class":3996},[3982,13628,10791],{"class":3992},[3982,13630,9430],{"class":3996},[3982,13632,6079],{"class":3992},[3982,13634,13635],{"class":3996},"[]> {\n",[3982,13637,13638,13640,13642,13644,13646,13648,13650,13652],{"class":3984,"line":4119},[3982,13639,5598],{"class":3988},[3982,13641,12399],{"class":5239},[3982,13643,5243],{"class":3996},[3982,13645,5246],{"class":5210},[3982,13647,6349],{"class":4003},[3982,13649,3823],{"class":3996},[3982,13651,12410],{"class":5253},[3982,13653,13654],{"class":3996},"\u003C{\n",[3982,13656,13657,13659,13661,13663],{"class":3984,"line":4135},[3982,13658,13284],{"class":4003},[3982,13660,4007],{"class":3996},[3982,13662,4010],{"class":3992},[3982,13664,4043],{"class":3996},[3982,13666,13667,13670,13672,13674],{"class":3984,"line":4859},[3982,13668,13669],{"class":4003},"      operation",[3982,13671,4007],{"class":3996},[3982,13673,4010],{"class":3992},[3982,13675,4043],{"class":3996},[3982,13677,13678,13681,13683,13685],{"class":3984,"line":4865},[3982,13679,13680],{"class":4003},"      resource",[3982,13682,4007],{"class":3996},[3982,13684,4010],{"class":3992},[3982,13686,4043],{"class":3996},[3982,13688,13689,13692,13694,13696],{"class":3984,"line":4871},[3982,13690,13691],{"class":4003},"      payload",[3982,13693,4007],{"class":3996},[3982,13695,4010],{"class":3992},[3982,13697,4043],{"class":3996},[3982,13699,13700,13703,13705,13707],{"class":3984,"line":4877},[3982,13701,13702],{"class":4003},"      createdAt",[3982,13704,4007],{"class":3996},[3982,13706,4094],{"class":3992},[3982,13708,4043],{"class":3996},[3982,13710,13711,13714,13716,13718],{"class":3984,"line":4883},[3982,13712,13713],{"class":4003},"      retryCount",[3982,13715,4007],{"class":3996},[3982,13717,4094],{"class":3992},[3982,13719,4043],{"class":3996},[3982,13721,13722,13725,13727,13729,13731,13733],{"class":3984,"line":4888},[3982,13723,13724],{"class":4003},"      lastError",[3982,13726,4007],{"class":3996},[3982,13728,4010],{"class":3992},[3982,13730,4032],{"class":3996},[3982,13732,12695],{"class":3992},[3982,13734,4043],{"class":3996},[3982,13736,13737,13740,13743],{"class":3984,"line":4893},[3982,13738,13739],{"class":3996},"    }>(",[3982,13741,13742],{"class":4028},"'SELECT * FROM outbox ORDER BY createdAt ASC'",[3982,13744,5375],{"class":3996},[3982,13746,13747],{"class":3984,"line":4899},[3982,13748,4832],{"emptyLinePlaceholder":4831},[3982,13750,13751,13753,13755,13757,13759,13761,13763,13765],{"class":3984,"line":4905},[3982,13752,5649],{"class":5210},[3982,13754,12399],{"class":4003},[3982,13756,3823],{"class":3996},[3982,13758,9790],{"class":5253},[3982,13760,5270],{"class":3996},[3982,13762,12437],{"class":4003},[3982,13764,5339],{"class":3988},[3982,13766,9451],{"class":3996},[3982,13768,13769,13771,13773],{"class":3984,"line":4911},[3982,13770,13274],{"class":3996},[3982,13772,12437],{"class":4003},[3982,13774,6287],{"class":3996},[3982,13776,13777,13780,13782,13784,13786,13788,13791,13793,13795,13797,13799],{"class":3984,"line":4916},[3982,13778,13779],{"class":4003},"      operation:",[3982,13781,12448],{"class":4003},[3982,13783,3823],{"class":3996},[3982,13785,6267],{"class":4003},[3982,13787,9981],{"class":5210},[3982,13789,13790],{"class":4028}," 'CREATE'",[3982,13792,4032],{"class":3996},[3982,13794,4035],{"class":4028},[3982,13796,4032],{"class":3996},[3982,13798,4040],{"class":4028},[3982,13800,6287],{"class":3996},[3982,13802,13803,13806,13808,13810,13812,13814,13817,13819,13821],{"class":3984,"line":4921},[3982,13804,13805],{"class":4003},"      resource:",[3982,13807,12448],{"class":4003},[3982,13809,3823],{"class":3996},[3982,13811,6245],{"class":4003},[3982,13813,9981],{"class":5210},[3982,13815,13816],{"class":4028}," 'trip'",[3982,13818,4032],{"class":3996},[3982,13820,4059],{"class":4028},[3982,13822,6287],{"class":3996},[3982,13824,13825,13828,13830,13832,13834,13836,13838,13840,13842],{"class":3984,"line":4927},[3982,13826,13827],{"class":4003},"      payload:",[3982,13829,6295],{"class":5239},[3982,13831,3823],{"class":3996},[3982,13833,9528],{"class":5253},[3982,13835,5270],{"class":3996},[3982,13837,12437],{"class":4003},[3982,13839,3823],{"class":3996},[3982,13841,6309],{"class":4003},[3982,13843,6021],{"class":3996},[3982,13845,13846,13848,13850,13852,13854,13856,13858],{"class":3984,"line":4933},[3982,13847,6557],{"class":4003},[3982,13849,12448],{"class":4003},[3982,13851,3823],{"class":3996},[3982,13853,4193],{"class":4003},[3982,13855,9847],{"class":3996},[3982,13857,10735],{"class":3988},[3982,13859,6287],{"class":3996},[3982,13861,13862],{"class":3984,"line":4938},[3982,13863,12634],{"class":3996},[3982,13865,13866],{"class":3984,"line":4943},[3982,13867,8502],{"class":3996},[3982,13869,13870],{"class":3984,"line":4949},[3982,13871,4832],{"emptyLinePlaceholder":4831},[3982,13873,13874,13876,13879,13881,13883,13885,13887,13889,13891,13893,13895,13897,13900,13902,13905,13907,13909,13911,13913],{"class":3984,"line":4954},[3982,13875,10495],{"class":3988},[3982,13877,13878],{"class":5253}," add",[3982,13880,5270],{"class":3996},[3982,13882,6074],{"class":4003},[3982,13884,4007],{"class":3996},[3982,13886,12955],{"class":3992},[3982,13888,9430],{"class":3996},[3982,13890,6079],{"class":3992},[3982,13892,3783],{"class":3996},[3982,13894,12964],{"class":4028},[3982,13896,4032],{"class":3996},[3982,13898,13899],{"class":4028},"'createdAt'",[3982,13901,4032],{"class":3996},[3982,13903,13904],{"class":4028},"'retryCount'",[3982,13906,12967],{"class":3996},[3982,13908,10791],{"class":3992},[3982,13910,9430],{"class":3996},[3982,13912,10796],{"class":3992},[3982,13914,10799],{"class":3996},[3982,13916,13917,13919,13921,13923,13926,13928,13930,13932,13934,13936,13938,13940,13942,13944,13946,13948,13950,13952,13954,13956,13958,13960,13962,13964,13966,13968,13970,13972,13974],{"class":3984,"line":4960},[3982,13918,5598],{"class":3988},[3982,13920,12991],{"class":5239},[3982,13922,5243],{"class":3996},[3982,13924,13925],{"class":4028},"`outbox-",[3982,13927,6237],{"class":3988},[3982,13929,9611],{"class":4003},[3982,13931,3823],{"class":6242},[3982,13933,9616],{"class":5253},[3982,13935,9619],{"class":6242},[3982,13937,6248],{"class":3988},[3982,13939,5768],{"class":4028},[3982,13941,6237],{"class":3988},[3982,13943,5986],{"class":4003},[3982,13945,3823],{"class":6242},[3982,13947,6647],{"class":5253},[3982,13949,5555],{"class":6242},[3982,13951,10646],{"class":5253},[3982,13953,5270],{"class":6242},[3982,13955,10651],{"class":6014},[3982,13957,4471],{"class":6242},[3982,13959,10656],{"class":5253},[3982,13961,5270],{"class":6242},[3982,13963,5937],{"class":6014},[3982,13965,3783],{"class":6242},[3982,13967,10665],{"class":6014},[3982,13969,7431],{"class":6242},[3982,13971,6248],{"class":3988},[3982,13973,6251],{"class":4028},[3982,13975,4043],{"class":3996},[3982,13977,13978,13980,13982,13984,13986],{"class":3984,"line":4966},[3982,13979,6515],{"class":5210},[3982,13981,6349],{"class":4003},[3982,13983,3823],{"class":3996},[3982,13985,13078],{"class":5253},[3982,13987,5994],{"class":3996},[3982,13989,13990,13993],{"class":3984,"line":4972},[3982,13991,13992],{"class":4028},"      'INSERT INTO outbox (id, operation, resource, payload, createdAt, retryCount) VALUES (?, ?, ?, ?, ?, ?)'",[3982,13994,6287],{"class":3996},[3982,13996,13997,13999,14001,14003,14005,14007,14009,14011,14013,14015,14017,14019,14021,14023,14025,14027,14029,14031,14033,14036,14038,14040,14042,14045,14047],{"class":3984,"line":4978},[3982,13998,13444],{"class":3996},[3982,14000,5166],{"class":4003},[3982,14002,3783],{"class":3996},[3982,14004,6074],{"class":4003},[3982,14006,3823],{"class":3996},[3982,14008,6267],{"class":4003},[3982,14010,3783],{"class":3996},[3982,14012,6074],{"class":4003},[3982,14014,3823],{"class":3996},[3982,14016,6245],{"class":4003},[3982,14018,3783],{"class":3996},[3982,14020,9523],{"class":5239},[3982,14022,3823],{"class":3996},[3982,14024,6300],{"class":5253},[3982,14026,5270],{"class":3996},[3982,14028,6074],{"class":4003},[3982,14030,3823],{"class":3996},[3982,14032,6309],{"class":4003},[3982,14034,14035],{"class":3996},"), ",[3982,14037,9611],{"class":4003},[3982,14039,3823],{"class":3996},[3982,14041,9616],{"class":5253},[3982,14043,14044],{"class":3996},"(), ",[3982,14046,13195],{"class":6014},[3982,14048,13473],{"class":3996},[3982,14050,14051],{"class":3984,"line":4983},[3982,14052,9868],{"class":3996},[3982,14054,14055],{"class":3984,"line":4989},[3982,14056,8502],{"class":3996},[3982,14058,14059],{"class":3984,"line":4995},[3982,14060,4832],{"emptyLinePlaceholder":4831},[3982,14062,14063,14065,14068,14070,14072,14074,14076,14078,14080,14082,14084,14086,14088,14090,14092],{"class":3984,"line":5001},[3982,14064,10495],{"class":3988},[3982,14066,14067],{"class":5253}," updateRetry",[3982,14069,5270],{"class":3996},[3982,14071,5166],{"class":4003},[3982,14073,4007],{"class":3996},[3982,14075,4010],{"class":3992},[3982,14077,3783],{"class":3996},[3982,14079,3789],{"class":4003},[3982,14081,4007],{"class":3996},[3982,14083,4010],{"class":3992},[3982,14085,10788],{"class":3996},[3982,14087,10791],{"class":3992},[3982,14089,9430],{"class":3996},[3982,14091,10796],{"class":3992},[3982,14093,10799],{"class":3996},[3982,14095,14096,14098,14100,14102,14104],{"class":3984,"line":5007},[3982,14097,6515],{"class":5210},[3982,14099,6349],{"class":4003},[3982,14101,3823],{"class":3996},[3982,14103,13078],{"class":5253},[3982,14105,5994],{"class":3996},[3982,14107,14108,14111],{"class":3984,"line":5013},[3982,14109,14110],{"class":4028},"      'UPDATE outbox SET retryCount = retryCount + 1, lastError = ? WHERE id = ?'",[3982,14112,6287],{"class":3996},[3982,14114,14115,14117,14119,14121,14123],{"class":3984,"line":5018},[3982,14116,13444],{"class":3996},[3982,14118,3789],{"class":4003},[3982,14120,3783],{"class":3996},[3982,14122,5166],{"class":4003},[3982,14124,13473],{"class":3996},[3982,14126,14127],{"class":3984,"line":5024},[3982,14128,9868],{"class":3996},[3982,14130,14131],{"class":3984,"line":5030},[3982,14132,8502],{"class":3996},[3982,14134,14135],{"class":3984,"line":5035},[3982,14136,4832],{"emptyLinePlaceholder":4831},[3982,14138,14139,14141,14143,14145,14147,14149,14151,14153,14155,14157,14159],{"class":3984,"line":8065},[3982,14140,10495],{"class":3988},[3982,14142,13492],{"class":5253},[3982,14144,5270],{"class":3996},[3982,14146,5166],{"class":4003},[3982,14148,4007],{"class":3996},[3982,14150,4010],{"class":3992},[3982,14152,10788],{"class":3996},[3982,14154,10791],{"class":3992},[3982,14156,9430],{"class":3996},[3982,14158,10796],{"class":3992},[3982,14160,10799],{"class":3996},[3982,14162,14163,14165,14167,14169,14171,14173,14176,14178,14180],{"class":3984,"line":8086},[3982,14164,6515],{"class":5210},[3982,14166,6349],{"class":4003},[3982,14168,3823],{"class":3996},[3982,14170,13078],{"class":5253},[3982,14172,5270],{"class":3996},[3982,14174,14175],{"class":4028},"'DELETE FROM outbox WHERE id = ?'",[3982,14177,12726],{"class":3996},[3982,14179,5166],{"class":4003},[3982,14181,10486],{"class":3996},[3982,14183,14184],{"class":3984,"line":8095},[3982,14185,8502],{"class":3996},[3982,14187,14188],{"class":3984,"line":8105},[3982,14189,4138],{"class":3996},[3973,14191,14194],{"className":3975,"code":14192,"filename":14193,"language":3977,"meta":3978,"style":3978},"import { useEffect, useState } from 'react';\nimport NetInfo from '@react-native-community\u002Fnetinfo';\n\nexport function useNetworkStatus() {\n  const [isOnline, setIsOnline] = useState(true);\n\n  useEffect(() => {\n    NetInfo.fetch().then(state => setIsOnline(state.isConnected ?? false));\n\n    const unsubscribe = NetInfo.addEventListener(state => {\n      setIsOnline(state.isConnected ?? false);\n    });\n\n    return unsubscribe;\n  }, []);\n\n  return isOnline;\n}\n","src\u002Fhooks\u002FuseNetworkStatus.ts",[3780,14195,14196,14216,14228,14232,14242,14264,14268,14278,14312,14316,14338,14356,14360,14364,14372,14376,14380,14388],{"__ignoreMap":3978},[3982,14197,14198,14200,14202,14204,14206,14208,14210,14212,14214],{"class":3984,"line":3985},[3982,14199,5211],{"class":5210},[3982,14201,5444],{"class":3996},[3982,14203,5447],{"class":4003},[3982,14205,3783],{"class":3996},[3982,14207,5452],{"class":4003},[3982,14209,5455],{"class":3996},[3982,14211,5458],{"class":5210},[3982,14213,5461],{"class":4028},[3982,14215,4043],{"class":3996},[3982,14217,14218,14220,14222,14224,14226],{"class":3984,"line":4000},[3982,14219,5211],{"class":5210},[3982,14221,5214],{"class":4003},[3982,14223,5217],{"class":5210},[3982,14225,5220],{"class":4028},[3982,14227,4043],{"class":3996},[3982,14229,14230],{"class":3984,"line":4020},[3982,14231,4832],{"emptyLinePlaceholder":4831},[3982,14233,14234,14236,14238,14240],{"class":3984,"line":4046},[3982,14235,5484],{"class":5210},[3982,14237,5487],{"class":3988},[3982,14239,5490],{"class":5253},[3982,14241,5493],{"class":3996},[3982,14243,14244,14246,14248,14250,14252,14254,14256,14258,14260,14262],{"class":3984,"line":4069},[3982,14245,5498],{"class":3988},[3982,14247,5501],{"class":3996},[3982,14249,5504],{"class":5239},[3982,14251,3783],{"class":3996},[3982,14253,5509],{"class":5239},[3982,14255,5512],{"class":3996},[3982,14257,5452],{"class":5253},[3982,14259,5270],{"class":3996},[3982,14261,5519],{"class":3988},[3982,14263,5375],{"class":3996},[3982,14265,14266],{"class":3984,"line":4086},[3982,14267,4832],{"emptyLinePlaceholder":4831},[3982,14269,14270,14272,14274,14276],{"class":3984,"line":4103},[3982,14271,5530],{"class":5253},[3982,14273,5533],{"class":3996},[3982,14275,5536],{"class":3988},[3982,14277,5342],{"class":3996},[3982,14279,14280,14282,14284,14286,14288,14290,14292,14294,14296,14298,14300,14302,14304,14306,14308,14310],{"class":3984,"line":4119},[3982,14281,5548],{"class":4003},[3982,14283,3823],{"class":3996},[3982,14285,5254],{"class":5253},[3982,14287,5555],{"class":3996},[3982,14289,5558],{"class":5253},[3982,14291,5270],{"class":3996},[3982,14293,5273],{"class":4003},[3982,14295,5339],{"class":3988},[3982,14297,5567],{"class":5253},[3982,14299,5270],{"class":3996},[3982,14301,5273],{"class":4003},[3982,14303,3823],{"class":3996},[3982,14305,5278],{"class":4003},[3982,14307,5578],{"class":3996},[3982,14309,5581],{"class":3988},[3982,14311,5584],{"class":3996},[3982,14313,14314],{"class":3984,"line":4135},[3982,14315,4832],{"emptyLinePlaceholder":4831},[3982,14317,14318,14320,14322,14324,14326,14328,14330,14332,14334,14336],{"class":3984,"line":4859},[3982,14319,5598],{"class":3988},[3982,14321,5322],{"class":5239},[3982,14323,5243],{"class":3996},[3982,14325,5327],{"class":4003},[3982,14327,3823],{"class":3996},[3982,14329,5332],{"class":5253},[3982,14331,5270],{"class":3996},[3982,14333,5273],{"class":4003},[3982,14335,5339],{"class":3988},[3982,14337,5342],{"class":3996},[3982,14339,14340,14342,14344,14346,14348,14350,14352,14354],{"class":3984,"line":4865},[3982,14341,5621],{"class":5253},[3982,14343,5270],{"class":3996},[3982,14345,5273],{"class":4003},[3982,14347,3823],{"class":3996},[3982,14349,5278],{"class":4003},[3982,14351,5578],{"class":3996},[3982,14353,5581],{"class":3988},[3982,14355,5375],{"class":3996},[3982,14357,14358],{"class":3984,"line":4871},[3982,14359,5640],{"class":3996},[3982,14361,14362],{"class":3984,"line":4877},[3982,14363,4832],{"emptyLinePlaceholder":4831},[3982,14365,14366,14368,14370],{"class":3984,"line":4883},[3982,14367,5649],{"class":5210},[3982,14369,5322],{"class":4003},[3982,14371,4043],{"class":3996},[3982,14373,14374],{"class":3984,"line":4888},[3982,14375,5658],{"class":3996},[3982,14377,14378],{"class":3984,"line":4893},[3982,14379,4832],{"emptyLinePlaceholder":4831},[3982,14381,14382,14384,14386],{"class":3984,"line":4899},[3982,14383,5667],{"class":5210},[3982,14385,5670],{"class":4003},[3982,14387,4043],{"class":3996},[3982,14389,14390],{"class":3984,"line":4905},[3982,14391,4852],{"class":3996},[3973,14393,14396],{"className":3975,"code":14394,"filename":14395,"language":3977,"meta":3978,"style":3978},"import { useEffect } from 'react';\nimport { useNetworkStatus } from '.\u002FuseNetworkStatus';\nimport { outboxDb, tripsDb } from '@\u002Fshared\u002Fdb';\nimport type { OutboxItem } from '@\u002Fshared\u002Ftypes';\nimport { Platform } from 'react-native';\nimport Constants from 'expo-constants';\nimport { tokenService } from '@\u002Ffeatures\u002Fauth\u002Fservices\u002FtokenService';\n\nconst SYNC_INTERVAL = 10000; \u002F\u002F 10 секунд\nconst BASE_RETRY_DELAY = 2000; \u002F\u002F 2 секунди\nconst MAX_RETRY_DELAY = 60000; \u002F\u002F 60 секунд\n\nconst getBaseUrl = (): string => {\n  if (Platform.OS === 'android') {\n    return 'http:\u002F\u002F10.0.2.2:3000';\n  }\n\n  const hostUri = Constants.expoConfig?.hostUri;\n  if (hostUri) {\n    const ip = hostUri.split(':').shift();\n    if (ip) return `http:\u002F\u002F${ip}:3000`;\n  }\n\n  return 'http:\u002F\u002Flocalhost:3000';\n};\n\nexport function useSyncWorker() {\n  const isOnline = useNetworkStatus();\n\n  useEffect(() => {\n    if (!isOnline) return;\n\n    const interval = setInterval(() => {\n      syncPendingItems();\n    }, SYNC_INTERVAL);\n\n    \u002F\u002F Одразу синхронізувати при появі мережі\n    syncPendingItems();\n\n    return () => clearInterval(interval);\n  }, [isOnline]);\n\n  async function syncPendingItems() {\n    const items = await outboxDb.getAll();\n\n    for (const item of items) {\n      await syncItem(item);\n    }\n  }\n\n  async function syncItem(item: OutboxItem) {\n    \u002F\u002F Exponential backoff\n    const delay = Math.min(\n      BASE_RETRY_DELAY * Math.pow(2, item.retryCount),\n      MAX_RETRY_DELAY\n    );\n\n    if (item.retryCount > 0) {\n      await new Promise(resolve => setTimeout(resolve, delay));\n    }\n\n    try {\n      \u002F\u002F Оновити статус на 'syncing'\n      if (item.resource === 'trip') {\n        await tripsDb.updateSyncStatus(item.payload.id as string, 'syncing');\n      }\n\n      \u002F\u002F Отримати токен\n      const token = await tokenService.getAccessToken();\n\n      \u002F\u002F Відправити на API\n      const response = await fetch(\n        `${getBaseUrl()}\u002F${item.resource}s`,\n        {\n          method: item.operation === 'CREATE' ? 'POST' : 'PATCH',\n          headers: {\n            'Content-Type': 'application\u002Fjson',\n            ...(token ? { Authorization: `Bearer ${token}` } : {}),\n          },\n          body: JSON.stringify(item.payload),\n        }\n      );\n\n      if (!response.ok) {\n        throw new Error(`HTTP ${response.status}: ${await response.text()}`);\n      }\n\n      const data = await response.json();\n\n      \u002F\u002F Успіх — оновити локальну базу\n      if (item.resource === 'trip') {\n        await tripsDb.updateSyncStatus(\n          item.payload.id as string,\n          'synced',\n          data.id\n        );\n      }\n\n      \u002F\u002F Видалити з outbox\n      await outboxDb.delete(item.id);\n    } catch (error) {\n      \u002F\u002F Помилка — оновити retry count\n      await outboxDb.updateRetry(item.id, (error as Error).message);\n\n      if (item.resource === 'trip') {\n        await tripsDb.updateSyncStatus(\n          item.payload.id as string,\n          'error',\n          undefined,\n          (error as Error).message\n        );\n      }\n    }\n  }\n}\n","src\u002Fhooks\u002FuseSyncWorker.ts",[3780,14397,14398,14414,14430,14453,14471,14488,14502,14520,14524,14541,14556,14571,14575,14591,14611,14620,14624,14628,14653,14663,14691,14718,14722,14726,14735,14739,14743,14753,14765,14769,14779,14793,14797,14813,14820,14829,14833,14838,14845,14849,14865,14873,14877,14888,14908,14912,14928,14941,14945,14949,14953,14971,14976,14992,15019,15024,15028,15032,15051,15077,15081,15085,15092,15097,15116,15150,15154,15158,15163,15184,15188,15193,15207,15239,15244,15269,15276,15288,15316,15321,15342,15346,15351,15355,15369,15413,15417,15421,15440,15444,15449,15467,15479,15498,15505,15514,15519,15523,15527,15532,15552,15564,15569,15602,15606,15624,15636,15654,15661,15668,15684,15688,15692,15696,15700],{"__ignoreMap":3978},[3982,14399,14400,14402,14404,14406,14408,14410,14412],{"class":3984,"line":3985},[3982,14401,5211],{"class":5210},[3982,14403,5444],{"class":3996},[3982,14405,5447],{"class":4003},[3982,14407,5455],{"class":3996},[3982,14409,5458],{"class":5210},[3982,14411,5461],{"class":4028},[3982,14413,4043],{"class":3996},[3982,14415,14416,14418,14420,14422,14424,14426,14428],{"class":3984,"line":4000},[3982,14417,5211],{"class":5210},[3982,14419,5444],{"class":3996},[3982,14421,5707],{"class":4003},[3982,14423,5455],{"class":3996},[3982,14425,5458],{"class":5210},[3982,14427,10313],{"class":4028},[3982,14429,4043],{"class":3996},[3982,14431,14432,14434,14436,14439,14441,14444,14446,14448,14451],{"class":3984,"line":4020},[3982,14433,5211],{"class":5210},[3982,14435,5444],{"class":3996},[3982,14437,14438],{"class":4003},"outboxDb",[3982,14440,3783],{"class":3996},[3982,14442,14443],{"class":4003},"tripsDb",[3982,14445,5455],{"class":3996},[3982,14447,5458],{"class":5210},[3982,14449,14450],{"class":4028}," '@\u002Fshared\u002Fdb'",[3982,14452,4043],{"class":3996},[3982,14454,14455,14457,14459,14461,14463,14465,14467,14469],{"class":3984,"line":4046},[3982,14456,5211],{"class":5210},[3982,14458,9171],{"class":5210},[3982,14460,5444],{"class":3996},[3982,14462,6079],{"class":4003},[3982,14464,5455],{"class":3996},[3982,14466,5458],{"class":5210},[3982,14468,12304],{"class":4028},[3982,14470,4043],{"class":3996},[3982,14472,14473,14475,14477,14480,14482,14484,14486],{"class":3984,"line":4069},[3982,14474,5211],{"class":5210},[3982,14476,5444],{"class":3996},[3982,14478,14479],{"class":4003},"Platform",[3982,14481,5455],{"class":3996},[3982,14483,5458],{"class":5210},[3982,14485,7565],{"class":4028},[3982,14487,4043],{"class":3996},[3982,14489,14490,14492,14495,14497,14500],{"class":3984,"line":4086},[3982,14491,5211],{"class":5210},[3982,14493,14494],{"class":4003}," Constants",[3982,14496,5217],{"class":5210},[3982,14498,14499],{"class":4028}," 'expo-constants'",[3982,14501,4043],{"class":3996},[3982,14503,14504,14506,14508,14511,14513,14515,14518],{"class":3984,"line":4103},[3982,14505,5211],{"class":5210},[3982,14507,5444],{"class":3996},[3982,14509,14510],{"class":4003},"tokenService",[3982,14512,5455],{"class":3996},[3982,14514,5458],{"class":5210},[3982,14516,14517],{"class":4028}," '@\u002Ffeatures\u002Fauth\u002Fservices\u002FtokenService'",[3982,14519,4043],{"class":3996},[3982,14521,14522],{"class":3984,"line":4119},[3982,14523,4832],{"emptyLinePlaceholder":4831},[3982,14525,14526,14528,14531,14533,14536,14538],{"class":3984,"line":4135},[3982,14527,5236],{"class":3988},[3982,14529,14530],{"class":5239}," SYNC_INTERVAL",[3982,14532,5243],{"class":3996},[3982,14534,14535],{"class":6014},"10000",[3982,14537,6096],{"class":3996},[3982,14539,14540],{"class":4016},"\u002F\u002F 10 секунд\n",[3982,14542,14543,14545,14548,14550,14552,14554],{"class":3984,"line":4859},[3982,14544,5236],{"class":3988},[3982,14546,14547],{"class":5239}," BASE_RETRY_DELAY",[3982,14549,5243],{"class":3996},[3982,14551,6093],{"class":6014},[3982,14553,6096],{"class":3996},[3982,14555,6099],{"class":4016},[3982,14557,14558,14560,14563,14565,14567,14569],{"class":3984,"line":4865},[3982,14559,5236],{"class":3988},[3982,14561,14562],{"class":5239}," MAX_RETRY_DELAY",[3982,14564,5243],{"class":3996},[3982,14566,6111],{"class":6014},[3982,14568,6096],{"class":3996},[3982,14570,6116],{"class":4016},[3982,14572,14573],{"class":3984,"line":4871},[3982,14574,4832],{"emptyLinePlaceholder":4831},[3982,14576,14577,14579,14582,14585,14587,14589],{"class":3984,"line":4877},[3982,14578,5236],{"class":3988},[3982,14580,14581],{"class":5253}," getBaseUrl",[3982,14583,14584],{"class":3996}," = (): ",[3982,14586,4010],{"class":3992},[3982,14588,5339],{"class":3988},[3982,14590,5342],{"class":3996},[3982,14592,14593,14595,14597,14599,14601,14604,14606,14609],{"class":3984,"line":4883},[3982,14594,5347],{"class":5210},[3982,14596,3778],{"class":3996},[3982,14598,14479],{"class":4003},[3982,14600,3823],{"class":3996},[3982,14602,14603],{"class":5239},"OS",[3982,14605,6270],{"class":3996},[3982,14607,14608],{"class":4028},"'android'",[3982,14610,5358],{"class":3996},[3982,14612,14613,14615,14618],{"class":3984,"line":4888},[3982,14614,5649],{"class":5210},[3982,14616,14617],{"class":4028}," 'http:\u002F\u002F10.0.2.2:3000'",[3982,14619,4043],{"class":3996},[3982,14621,14622],{"class":3984,"line":4893},[3982,14623,5417],{"class":3996},[3982,14625,14626],{"class":3984,"line":4899},[3982,14627,4832],{"emptyLinePlaceholder":4831},[3982,14629,14630,14632,14635,14637,14640,14642,14645,14648,14651],{"class":3984,"line":4905},[3982,14631,5498],{"class":3988},[3982,14633,14634],{"class":5239}," hostUri",[3982,14636,5243],{"class":3996},[3982,14638,14639],{"class":4003},"Constants",[3982,14641,3823],{"class":3996},[3982,14643,14644],{"class":4003},"expoConfig",[3982,14646,14647],{"class":3996},"?.",[3982,14649,14650],{"class":4003},"hostUri",[3982,14652,4043],{"class":3996},[3982,14654,14655,14657,14659,14661],{"class":3984,"line":4911},[3982,14656,5347],{"class":5210},[3982,14658,3778],{"class":3996},[3982,14660,14650],{"class":4003},[3982,14662,5358],{"class":3996},[3982,14664,14665,14667,14670,14672,14674,14676,14679,14681,14684,14686,14689],{"class":3984,"line":4916},[3982,14666,5598],{"class":3988},[3982,14668,14669],{"class":5239}," ip",[3982,14671,5243],{"class":3996},[3982,14673,14650],{"class":4003},[3982,14675,3823],{"class":3996},[3982,14677,14678],{"class":5253},"split",[3982,14680,5270],{"class":3996},[3982,14682,14683],{"class":4028},"':'",[3982,14685,4471],{"class":3996},[3982,14687,14688],{"class":5253},"shift",[3982,14690,5257],{"class":3996},[3982,14692,14693,14695,14697,14700,14702,14704,14707,14709,14711,14713,14716],{"class":3984,"line":4921},[3982,14694,6324],{"class":5210},[3982,14696,3778],{"class":3996},[3982,14698,14699],{"class":4003},"ip",[3982,14701,9317],{"class":3996},[3982,14703,10389],{"class":5210},[3982,14705,14706],{"class":4028}," `http:\u002F\u002F",[3982,14708,6237],{"class":3988},[3982,14710,14699],{"class":4003},[3982,14712,6248],{"class":3988},[3982,14714,14715],{"class":4028},":3000`",[3982,14717,4043],{"class":3996},[3982,14719,14720],{"class":3984,"line":4927},[3982,14721,5417],{"class":3996},[3982,14723,14724],{"class":3984,"line":4933},[3982,14725,4832],{"emptyLinePlaceholder":4831},[3982,14727,14728,14730,14733],{"class":3984,"line":4938},[3982,14729,5667],{"class":5210},[3982,14731,14732],{"class":4028}," 'http:\u002F\u002Flocalhost:3000'",[3982,14734,4043],{"class":3996},[3982,14736,14737],{"class":3984,"line":4943},[3982,14738,4138],{"class":3996},[3982,14740,14741],{"class":3984,"line":4949},[3982,14742,4832],{"emptyLinePlaceholder":4831},[3982,14744,14745,14747,14749,14751],{"class":3984,"line":4954},[3982,14746,5484],{"class":5210},[3982,14748,5487],{"class":3988},[3982,14750,10328],{"class":5253},[3982,14752,5493],{"class":3996},[3982,14754,14755,14757,14759,14761,14763],{"class":3984,"line":4960},[3982,14756,5498],{"class":3988},[3982,14758,5670],{"class":5239},[3982,14760,5243],{"class":3996},[3982,14762,5707],{"class":5253},[3982,14764,5257],{"class":3996},[3982,14766,14767],{"class":3984,"line":4966},[3982,14768,4832],{"emptyLinePlaceholder":4831},[3982,14770,14771,14773,14775,14777],{"class":3984,"line":4972},[3982,14772,5530],{"class":5253},[3982,14774,5533],{"class":3996},[3982,14776,5536],{"class":3988},[3982,14778,5342],{"class":3996},[3982,14780,14781,14783,14785,14787,14789,14791],{"class":3984,"line":4978},[3982,14782,6324],{"class":5210},[3982,14784,10382],{"class":3996},[3982,14786,5504],{"class":4003},[3982,14788,9317],{"class":3996},[3982,14790,10389],{"class":5210},[3982,14792,4043],{"class":3996},[3982,14794,14795],{"class":3984,"line":4983},[3982,14796,4832],{"emptyLinePlaceholder":4831},[3982,14798,14799,14801,14803,14805,14807,14809,14811],{"class":3984,"line":4989},[3982,14800,5598],{"class":3988},[3982,14802,10402],{"class":5239},[3982,14804,5243],{"class":3996},[3982,14806,10407],{"class":5253},[3982,14808,5533],{"class":3996},[3982,14810,5536],{"class":3988},[3982,14812,5342],{"class":3996},[3982,14814,14815,14818],{"class":3984,"line":4995},[3982,14816,14817],{"class":5253},"      syncPendingItems",[3982,14819,5257],{"class":3996},[3982,14821,14822,14824,14827],{"class":3984,"line":5001},[3982,14823,10425],{"class":3996},[3982,14825,14826],{"class":5239},"SYNC_INTERVAL",[3982,14828,5375],{"class":3996},[3982,14830,14831],{"class":3984,"line":5007},[3982,14832,4832],{"emptyLinePlaceholder":4831},[3982,14834,14835],{"class":3984,"line":5013},[3982,14836,14837],{"class":4016},"    \u002F\u002F Одразу синхронізувати при появі мережі\n",[3982,14839,14840,14843],{"class":3984,"line":5018},[3982,14841,14842],{"class":5253},"    syncPendingItems",[3982,14844,5257],{"class":3996},[3982,14846,14847],{"class":3984,"line":5024},[3982,14848,4832],{"emptyLinePlaceholder":4831},[3982,14850,14851,14853,14855,14857,14859,14861,14863],{"class":3984,"line":5030},[3982,14852,5649],{"class":5210},[3982,14854,9472],{"class":3996},[3982,14856,5536],{"class":3988},[3982,14858,10465],{"class":5253},[3982,14860,5270],{"class":3996},[3982,14862,10470],{"class":4003},[3982,14864,5375],{"class":3996},[3982,14866,14867,14869,14871],{"class":3984,"line":5035},[3982,14868,10477],{"class":3996},[3982,14870,5504],{"class":4003},[3982,14872,10486],{"class":3996},[3982,14874,14875],{"class":3984,"line":8065},[3982,14876,4832],{"emptyLinePlaceholder":4831},[3982,14878,14879,14881,14883,14886],{"class":3984,"line":8086},[3982,14880,10495],{"class":3988},[3982,14882,5487],{"class":3988},[3982,14884,14885],{"class":5253}," syncPendingItems",[3982,14887,5493],{"class":3996},[3982,14889,14890,14892,14895,14897,14899,14901,14903,14906],{"class":3984,"line":8095},[3982,14891,5598],{"class":3988},[3982,14893,14894],{"class":5239}," items",[3982,14896,5243],{"class":3996},[3982,14898,5246],{"class":5210},[3982,14900,13616],{"class":4003},[3982,14902,3823],{"class":3996},[3982,14904,14905],{"class":5253},"getAll",[3982,14907,5257],{"class":3996},[3982,14909,14910],{"class":3984,"line":8105},[3982,14911,4832],{"emptyLinePlaceholder":4831},[3982,14913,14914,14916,14918,14920,14922,14924,14926],{"class":3984,"line":8110},[3982,14915,10549],{"class":5210},[3982,14917,3778],{"class":3996},[3982,14919,5236],{"class":3988},[3982,14921,6262],{"class":5239},[3982,14923,10559],{"class":3988},[3982,14925,14894],{"class":4003},[3982,14927,5358],{"class":3996},[3982,14929,14930,14932,14935,14937,14939],{"class":3984,"line":8120},[3982,14931,6346],{"class":5210},[3982,14933,14934],{"class":5253}," syncItem",[3982,14936,5270],{"class":3996},[3982,14938,6074],{"class":4003},[3982,14940,5375],{"class":3996},[3982,14942,14943],{"class":3984,"line":8128},[3982,14944,6492],{"class":3996},[3982,14946,14947],{"class":3984,"line":8140},[3982,14948,5417],{"class":3996},[3982,14950,14951],{"class":3984,"line":8153},[3982,14952,4832],{"emptyLinePlaceholder":4831},[3982,14954,14955,14957,14959,14961,14963,14965,14967,14969],{"class":3984,"line":8167},[3982,14956,10495],{"class":3988},[3982,14958,5487],{"class":3988},[3982,14960,14934],{"class":5253},[3982,14962,5270],{"class":3996},[3982,14964,6074],{"class":4003},[3982,14966,4007],{"class":3996},[3982,14968,6079],{"class":3992},[3982,14970,5358],{"class":3996},[3982,14972,14973],{"class":3984,"line":8183},[3982,14974,14975],{"class":4016},"    \u002F\u002F Exponential backoff\n",[3982,14977,14978,14980,14982,14984,14986,14988,14990],{"class":3984,"line":8208},[3982,14979,5598],{"class":3988},[3982,14981,5981],{"class":5239},[3982,14983,5243],{"class":3996},[3982,14985,5986],{"class":4003},[3982,14987,3823],{"class":3996},[3982,14989,5991],{"class":5253},[3982,14991,5994],{"class":3996},[3982,14993,14994,14997,14999,15001,15003,15005,15007,15009,15011,15013,15015,15017],{"class":3984,"line":8223},[3982,14995,14996],{"class":5239},"      BASE_RETRY_DELAY",[3982,14998,6002],{"class":3996},[3982,15000,5986],{"class":4003},[3982,15002,3823],{"class":3996},[3982,15004,6009],{"class":5253},[3982,15006,5270],{"class":3996},[3982,15008,5937],{"class":6014},[3982,15010,3783],{"class":3996},[3982,15012,6074],{"class":4003},[3982,15014,3823],{"class":3996},[3982,15016,4189],{"class":4003},[3982,15018,6021],{"class":3996},[3982,15020,15021],{"class":3984,"line":8241},[3982,15022,15023],{"class":5239},"      MAX_RETRY_DELAY\n",[3982,15025,15026],{"class":3984,"line":8271},[3982,15027,9868],{"class":3996},[3982,15029,15030],{"class":3984,"line":8277},[3982,15031,4832],{"emptyLinePlaceholder":4831},[3982,15033,15034,15036,15038,15040,15042,15044,15047,15049],{"class":3984,"line":8294},[3982,15035,6324],{"class":5210},[3982,15037,3778],{"class":3996},[3982,15039,6074],{"class":4003},[3982,15041,3823],{"class":3996},[3982,15043,4189],{"class":4003},[3982,15045,15046],{"class":3996}," > ",[3982,15048,13195],{"class":6014},[3982,15050,5358],{"class":3996},[3982,15052,15053,15055,15057,15059,15061,15063,15065,15067,15069,15071,15073,15075],{"class":3984,"line":8308},[3982,15054,6346],{"class":5210},[3982,15056,6180],{"class":3988},[3982,15058,6183],{"class":3992},[3982,15060,5270],{"class":3996},[3982,15062,6188],{"class":4003},[3982,15064,5339],{"class":3988},[3982,15066,6193],{"class":5253},[3982,15068,5270],{"class":3996},[3982,15070,6188],{"class":4003},[3982,15072,3783],{"class":3996},[3982,15074,6202],{"class":4003},[3982,15076,5584],{"class":3996},[3982,15078,15079],{"class":3984,"line":8313},[3982,15080,6492],{"class":3996},[3982,15082,15083],{"class":3984,"line":8319},[3982,15084,4832],{"emptyLinePlaceholder":4831},[3982,15086,15087,15090],{"class":3984,"line":8325},[3982,15088,15089],{"class":5210},"    try",[3982,15091,5342],{"class":3996},[3982,15093,15094],{"class":3984,"line":8330},[3982,15095,15096],{"class":4016},"      \u002F\u002F Оновити статус на 'syncing'\n",[3982,15098,15099,15102,15104,15106,15108,15110,15112,15114],{"class":3984,"line":8336},[3982,15100,15101],{"class":5210},"      if",[3982,15103,3778],{"class":3996},[3982,15105,6074],{"class":4003},[3982,15107,3823],{"class":3996},[3982,15109,6245],{"class":4003},[3982,15111,6270],{"class":3996},[3982,15113,4054],{"class":4028},[3982,15115,5358],{"class":3996},[3982,15117,15118,15120,15122,15124,15127,15129,15131,15133,15135,15137,15139,15141,15144,15146,15148],{"class":3984,"line":8342},[3982,15119,10603],{"class":5210},[3982,15121,12345],{"class":4003},[3982,15123,3823],{"class":3996},[3982,15125,15126],{"class":5253},"updateSyncStatus",[3982,15128,5270],{"class":3996},[3982,15130,6074],{"class":4003},[3982,15132,3823],{"class":3996},[3982,15134,6309],{"class":4003},[3982,15136,3823],{"class":3996},[3982,15138,5166],{"class":4003},[3982,15140,9981],{"class":5210},[3982,15142,15143],{"class":3992}," string",[3982,15145,3783],{"class":3996},[3982,15147,4275],{"class":4028},[3982,15149,5375],{"class":3996},[3982,15151,15152],{"class":3984,"line":8348},[3982,15153,10756],{"class":3996},[3982,15155,15156],{"class":3984,"line":8354},[3982,15157,4832],{"emptyLinePlaceholder":4831},[3982,15159,15160],{"class":3984,"line":8360},[3982,15161,15162],{"class":4016},"      \u002F\u002F Отримати токен\n",[3982,15164,15165,15167,15170,15172,15174,15177,15179,15182],{"class":3984,"line":8366},[3982,15166,9515],{"class":3988},[3982,15168,15169],{"class":5239}," token",[3982,15171,5243],{"class":3996},[3982,15173,5246],{"class":5210},[3982,15175,15176],{"class":4003}," tokenService",[3982,15178,3823],{"class":3996},[3982,15180,15181],{"class":5253},"getAccessToken",[3982,15183,5257],{"class":3996},[3982,15185,15186],{"class":3984,"line":8372},[3982,15187,4832],{"emptyLinePlaceholder":4831},[3982,15189,15190],{"class":3984,"line":8377},[3982,15191,15192],{"class":4016},"      \u002F\u002F Відправити на API\n",[3982,15194,15195,15197,15199,15201,15203,15205],{"class":3984,"line":8383},[3982,15196,9515],{"class":3988},[3982,15198,6222],{"class":5239},[3982,15200,5243],{"class":3996},[3982,15202,5246],{"class":5210},[3982,15204,6229],{"class":5253},[3982,15206,5994],{"class":3996},[3982,15208,15209,15212,15214,15217,15219,15221,15224,15226,15228,15230,15232,15234,15237],{"class":3984,"line":8389},[3982,15210,15211],{"class":4028},"        `",[3982,15213,6237],{"class":3988},[3982,15215,15216],{"class":5253},"getBaseUrl",[3982,15218,9619],{"class":6242},[3982,15220,6248],{"class":3988},[3982,15222,15223],{"class":4028},"\u002F",[3982,15225,6237],{"class":3988},[3982,15227,6074],{"class":4003},[3982,15229,3823],{"class":6242},[3982,15231,6245],{"class":4003},[3982,15233,6248],{"class":3988},[3982,15235,15236],{"class":4028},"s`",[3982,15238,6287],{"class":3996},[3982,15240,15241],{"class":3984,"line":8395},[3982,15242,15243],{"class":3996},"        {\n",[3982,15245,15246,15249,15251,15253,15255,15257,15259,15261,15263,15265,15267],{"class":3984,"line":8401},[3982,15247,15248],{"class":4003},"          method:",[3982,15250,6262],{"class":4003},[3982,15252,3823],{"class":3996},[3982,15254,6267],{"class":4003},[3982,15256,6270],{"class":3996},[3982,15258,4029],{"class":4028},[3982,15260,6275],{"class":3996},[3982,15262,6278],{"class":4028},[3982,15264,6281],{"class":3996},[3982,15266,6284],{"class":4028},[3982,15268,6287],{"class":3996},[3982,15270,15271,15274],{"class":3984,"line":8407},[3982,15272,15273],{"class":4003},"          headers:",[3982,15275,5342],{"class":3996},[3982,15277,15278,15281,15283,15286],{"class":3984,"line":8413},[3982,15279,15280],{"class":4028},"            'Content-Type'",[3982,15282,6753],{"class":4003},[3982,15284,15285],{"class":4028}," 'application\u002Fjson'",[3982,15287,6287],{"class":3996},[3982,15289,15290,15293,15296,15299,15302,15305,15307,15309,15311,15313],{"class":3984,"line":8418},[3982,15291,15292],{"class":3996},"            ...(",[3982,15294,15295],{"class":4003},"token",[3982,15297,15298],{"class":3996}," ? { ",[3982,15300,15301],{"class":4003},"Authorization:",[3982,15303,15304],{"class":4028}," `Bearer ",[3982,15306,6237],{"class":3988},[3982,15308,15295],{"class":4003},[3982,15310,6248],{"class":3988},[3982,15312,6251],{"class":4028},[3982,15314,15315],{"class":3996}," } : {}),\n",[3982,15317,15318],{"class":3984,"line":8423},[3982,15319,15320],{"class":3996},"          },\n",[3982,15322,15323,15326,15328,15330,15332,15334,15336,15338,15340],{"class":3984,"line":8428},[3982,15324,15325],{"class":4003},"          body:",[3982,15327,6295],{"class":5239},[3982,15329,3823],{"class":3996},[3982,15331,6300],{"class":5253},[3982,15333,5270],{"class":3996},[3982,15335,6074],{"class":4003},[3982,15337,3823],{"class":3996},[3982,15339,6309],{"class":4003},[3982,15341,6021],{"class":3996},[3982,15343,15344],{"class":3984,"line":8434},[3982,15345,10898],{"class":3996},[3982,15347,15348],{"class":3984,"line":8458},[3982,15349,15350],{"class":3996},"      );\n",[3982,15352,15353],{"class":3984,"line":8466},[3982,15354,4832],{"emptyLinePlaceholder":4831},[3982,15356,15357,15359,15361,15363,15365,15367],{"class":3984,"line":8477},[3982,15358,15101],{"class":5210},[3982,15360,10382],{"class":3996},[3982,15362,6329],{"class":4003},[3982,15364,3823],{"class":3996},[3982,15366,6334],{"class":4003},[3982,15368,5358],{"class":3996},[3982,15370,15371,15374,15376,15378,15380,15383,15385,15387,15389,15391,15393,15395,15397,15399,15401,15403,15405,15407,15409,15411],{"class":3984,"line":8488},[3982,15372,15373],{"class":5210},"        throw",[3982,15375,6180],{"class":3988},[3982,15377,10745],{"class":5253},[3982,15379,5270],{"class":3996},[3982,15381,15382],{"class":4028},"`HTTP ",[3982,15384,6237],{"class":3988},[3982,15386,6329],{"class":4003},[3982,15388,3823],{"class":6242},[3982,15390,9342],{"class":4003},[3982,15392,6248],{"class":3988},[3982,15394,4007],{"class":4028},[3982,15396,6237],{"class":3988},[3982,15398,5246],{"class":5210},[3982,15400,6222],{"class":4003},[3982,15402,3823],{"class":6242},[3982,15404,6479],{"class":5253},[3982,15406,9619],{"class":6242},[3982,15408,6248],{"class":3988},[3982,15410,6251],{"class":4028},[3982,15412,5375],{"class":3996},[3982,15414,15415],{"class":3984,"line":8499},[3982,15416,10756],{"class":3996},[3982,15418,15419],{"class":3984,"line":8505},[3982,15420,4832],{"emptyLinePlaceholder":4831},[3982,15422,15423,15425,15428,15430,15432,15434,15436,15438],{"class":3984,"line":8529},[3982,15424,9515],{"class":3988},[3982,15426,15427],{"class":5239}," data",[3982,15429,5243],{"class":3996},[3982,15431,5246],{"class":5210},[3982,15433,6222],{"class":4003},[3982,15435,3823],{"class":3996},[3982,15437,6933],{"class":5253},[3982,15439,5257],{"class":3996},[3982,15441,15442],{"class":3984,"line":8537},[3982,15443,4832],{"emptyLinePlaceholder":4831},[3982,15445,15446],{"class":3984,"line":8548},[3982,15447,15448],{"class":4016},"      \u002F\u002F Успіх — оновити локальну базу\n",[3982,15450,15451,15453,15455,15457,15459,15461,15463,15465],{"class":3984,"line":8559},[3982,15452,15101],{"class":5210},[3982,15454,3778],{"class":3996},[3982,15456,6074],{"class":4003},[3982,15458,3823],{"class":3996},[3982,15460,6245],{"class":4003},[3982,15462,6270],{"class":3996},[3982,15464,4054],{"class":4028},[3982,15466,5358],{"class":3996},[3982,15468,15469,15471,15473,15475,15477],{"class":3984,"line":8569},[3982,15470,10603],{"class":5210},[3982,15472,12345],{"class":4003},[3982,15474,3823],{"class":3996},[3982,15476,15126],{"class":5253},[3982,15478,5994],{"class":3996},[3982,15480,15481,15484,15486,15488,15490,15492,15494,15496],{"class":3984,"line":8574},[3982,15482,15483],{"class":4003},"          item",[3982,15485,3823],{"class":3996},[3982,15487,6309],{"class":4003},[3982,15489,3823],{"class":3996},[3982,15491,5166],{"class":4003},[3982,15493,9981],{"class":5210},[3982,15495,15143],{"class":3992},[3982,15497,6287],{"class":3996},[3982,15499,15500,15503],{"class":3984,"line":8582},[3982,15501,15502],{"class":4028},"          'synced'",[3982,15504,6287],{"class":3996},[3982,15506,15507,15510,15512],{"class":3984,"line":8593},[3982,15508,15509],{"class":4003},"          data",[3982,15511,3823],{"class":3996},[3982,15513,9815],{"class":4003},[3982,15515,15516],{"class":3984,"line":8602},[3982,15517,15518],{"class":3996},"        );\n",[3982,15520,15521],{"class":3984,"line":8613},[3982,15522,10756],{"class":3996},[3982,15524,15525],{"class":3984,"line":8618},[3982,15526,4832],{"emptyLinePlaceholder":4831},[3982,15528,15529],{"class":3984,"line":8626},[3982,15530,15531],{"class":4016},"      \u002F\u002F Видалити з outbox\n",[3982,15533,15534,15536,15538,15540,15542,15544,15546,15548,15550],{"class":3984,"line":8636},[3982,15535,6346],{"class":5210},[3982,15537,13616],{"class":4003},[3982,15539,3823],{"class":3996},[3982,15541,6358],{"class":5253},[3982,15543,5270],{"class":3996},[3982,15545,6074],{"class":4003},[3982,15547,3823],{"class":3996},[3982,15549,5166],{"class":4003},[3982,15551,5375],{"class":3996},[3982,15553,15554,15556,15558,15560,15562],{"class":3984,"line":8645},[3982,15555,6413],{"class":3996},[3982,15557,6499],{"class":5210},[3982,15559,3778],{"class":3996},[3982,15561,3789],{"class":4003},[3982,15563,5358],{"class":3996},[3982,15565,15566],{"class":3984,"line":8655},[3982,15567,15568],{"class":4016},"      \u002F\u002F Помилка — оновити retry count\n",[3982,15570,15571,15573,15575,15577,15580,15582,15584,15586,15588,15590,15592,15594,15596,15598,15600],{"class":3984,"line":8665},[3982,15572,6346],{"class":5210},[3982,15574,13616],{"class":4003},[3982,15576,3823],{"class":3996},[3982,15578,15579],{"class":5253},"updateRetry",[3982,15581,5270],{"class":3996},[3982,15583,6074],{"class":4003},[3982,15585,3823],{"class":3996},[3982,15587,5166],{"class":4003},[3982,15589,10738],{"class":3996},[3982,15591,3789],{"class":4003},[3982,15593,9981],{"class":5210},[3982,15595,10745],{"class":3992},[3982,15597,4471],{"class":3996},[3982,15599,6565],{"class":4003},[3982,15601,5375],{"class":3996},[3982,15603,15604],{"class":3984,"line":8676},[3982,15605,4832],{"emptyLinePlaceholder":4831},[3982,15607,15608,15610,15612,15614,15616,15618,15620,15622],{"class":3984,"line":8686},[3982,15609,15101],{"class":5210},[3982,15611,3778],{"class":3996},[3982,15613,6074],{"class":4003},[3982,15615,3823],{"class":3996},[3982,15617,6245],{"class":4003},[3982,15619,6270],{"class":3996},[3982,15621,4054],{"class":4028},[3982,15623,5358],{"class":3996},[3982,15625,15626,15628,15630,15632,15634],{"class":3984,"line":8697},[3982,15627,10603],{"class":5210},[3982,15629,12345],{"class":4003},[3982,15631,3823],{"class":3996},[3982,15633,15126],{"class":5253},[3982,15635,5994],{"class":3996},[3982,15637,15638,15640,15642,15644,15646,15648,15650,15652],{"class":3984,"line":8702},[3982,15639,15483],{"class":4003},[3982,15641,3823],{"class":3996},[3982,15643,6309],{"class":4003},[3982,15645,3823],{"class":3996},[3982,15647,5166],{"class":4003},[3982,15649,9981],{"class":5210},[3982,15651,15143],{"class":3992},[3982,15653,6287],{"class":3996},[3982,15655,15656,15659],{"class":3984,"line":8710},[3982,15657,15658],{"class":4028},"          'error'",[3982,15660,6287],{"class":3996},[3982,15662,15663,15666],{"class":3984,"line":8720},[3982,15664,15665],{"class":3988},"          undefined",[3982,15667,6287],{"class":3996},[3982,15669,15670,15673,15675,15677,15679,15681],{"class":3984,"line":8731},[3982,15671,15672],{"class":3996},"          (",[3982,15674,3789],{"class":4003},[3982,15676,9981],{"class":5210},[3982,15678,10745],{"class":3992},[3982,15680,4471],{"class":3996},[3982,15682,15683],{"class":4003},"message\n",[3982,15685,15686],{"class":3984,"line":8741},[3982,15687,15518],{"class":3996},[3982,15689,15690],{"class":3984,"line":8750},[3982,15691,10756],{"class":3996},[3982,15693,15694],{"class":3984,"line":8759},[3982,15695,6492],{"class":3996},[3982,15697,15698],{"class":3984,"line":8769},[3982,15699,5417],{"class":3996},[3982,15701,15702],{"class":3984,"line":8774},[3982,15703,4852],{"class":3996},[3973,15705,15708],{"className":3975,"code":15706,"filename":15707,"language":3977,"meta":3978,"style":3978},"import { View, Text, StyleSheet } from 'react-native';\nimport { useNetworkStatus } from '@\u002Fhooks\u002FuseNetworkStatus';\n\nexport function OfflineBanner() {\n  const isOnline = useNetworkStatus();\n\n  if (isOnline) return null;\n\n  return (\n    \u003CView style={styles.container}>\n      \u003CText style={styles.icon}>📡\u003C\u002FText>\n      \u003CText style={styles.text}>\n        Офлайн-режим. Зміни синхронізуються автоматично при появі мережі.\n      \u003C\u002FText>\n    \u003C\u002FView>\n  );\n}\n\nconst styles = StyleSheet.create({\n  container: {\n    backgroundColor: '#FFA726',\n    flexDirection: 'row',\n    alignItems: 'center',\n    paddingHorizontal: 16,\n    paddingVertical: 12,\n    gap: 8,\n  },\n  icon: {\n    fontSize: 18,\n  },\n  text: {\n    flex: 1,\n    color: '#fff',\n    fontSize: 14,\n    fontWeight: '600',\n  },\n});\n","src\u002Fcomponents\u002FOfflineBanner.tsx",[3780,15709,15710,15734,15751,15755,15766,15778,15782,15798,15802,15808,15822,15842,15856,15881,15889,15897,15901,15905,15909,15927,15933,15941,15949,15957,15965,15973,15981,15985,15992,16001,16005,16012,16020,16028,16037,16045,16049],{"__ignoreMap":3978},[3982,15711,15712,15714,15716,15718,15720,15722,15724,15726,15728,15730,15732],{"class":3984,"line":3985},[3982,15713,5211],{"class":5210},[3982,15715,5444],{"class":3996},[3982,15717,5728],{"class":4003},[3982,15719,3783],{"class":3996},[3982,15721,7538],{"class":4003},[3982,15723,3783],{"class":3996},[3982,15725,7558],{"class":4003},[3982,15727,5455],{"class":3996},[3982,15729,5458],{"class":5210},[3982,15731,7565],{"class":4028},[3982,15733,4043],{"class":3996},[3982,15735,15736,15738,15740,15742,15744,15746,15749],{"class":3984,"line":4000},[3982,15737,5211],{"class":5210},[3982,15739,5444],{"class":3996},[3982,15741,5707],{"class":4003},[3982,15743,5455],{"class":3996},[3982,15745,5458],{"class":5210},[3982,15747,15748],{"class":4028}," '@\u002Fhooks\u002FuseNetworkStatus'",[3982,15750,4043],{"class":3996},[3982,15752,15753],{"class":3984,"line":4020},[3982,15754,4832],{"emptyLinePlaceholder":4831},[3982,15756,15757,15759,15761,15764],{"class":3984,"line":4046},[3982,15758,5484],{"class":5210},[3982,15760,5487],{"class":3988},[3982,15762,15763],{"class":5253}," OfflineBanner",[3982,15765,5493],{"class":3996},[3982,15767,15768,15770,15772,15774,15776],{"class":3984,"line":4069},[3982,15769,5498],{"class":3988},[3982,15771,5670],{"class":5239},[3982,15773,5243],{"class":3996},[3982,15775,5707],{"class":5253},[3982,15777,5257],{"class":3996},[3982,15779,15780],{"class":3984,"line":4086},[3982,15781,4832],{"emptyLinePlaceholder":4831},[3982,15783,15784,15786,15788,15790,15792,15794,15796],{"class":3984,"line":4103},[3982,15785,5347],{"class":5210},[3982,15787,3778],{"class":3996},[3982,15789,5504],{"class":4003},[3982,15791,9317],{"class":3996},[3982,15793,10389],{"class":5210},[3982,15795,12745],{"class":3988},[3982,15797,4043],{"class":3996},[3982,15799,15800],{"class":3984,"line":4119},[3982,15801,4832],{"emptyLinePlaceholder":4831},[3982,15803,15804,15806],{"class":3984,"line":4135},[3982,15805,5667],{"class":5210},[3982,15807,5720],{"class":3996},[3982,15809,15810,15812,15814,15816,15818,15820],{"class":3984,"line":4859},[3982,15811,5725],{"class":3996},[3982,15813,5728],{"class":4003},[3982,15815,7822],{"class":4003},[3982,15817,7825],{"class":3996},[3982,15819,7828],{"class":4003},[3982,15821,7831],{"class":3996},[3982,15823,15824,15826,15828,15830,15832,15835,15838,15840],{"class":3984,"line":4865},[3982,15825,7915],{"class":3996},[3982,15827,7538],{"class":4003},[3982,15829,7822],{"class":4003},[3982,15831,7825],{"class":3996},[3982,15833,15834],{"class":4003},"icon",[3982,15836,15837],{"class":3996},"}>📡\u003C\u002F",[3982,15839,7538],{"class":4003},[3982,15841,5731],{"class":3996},[3982,15843,15844,15846,15848,15850,15852,15854],{"class":3984,"line":4871},[3982,15845,7915],{"class":3996},[3982,15847,7538],{"class":4003},[3982,15849,7822],{"class":4003},[3982,15851,7825],{"class":3996},[3982,15853,6479],{"class":4003},[3982,15855,7831],{"class":3996},[3982,15857,15858,15861,15863,15865,15867,15869,15871,15873,15875,15877,15879],{"class":3984,"line":4877},[3982,15859,15860],{"class":4003},"        Офлайн",[3982,15862,5768],{"class":3996},[3982,15864,5771],{"class":4003},[3982,15866,5774],{"class":3996},[3982,15868,5777],{"class":4003},[3982,15870,5780],{"class":4003},[3982,15872,5783],{"class":4003},[3982,15874,5786],{"class":4003},[3982,15876,5789],{"class":4003},[3982,15878,5792],{"class":4003},[3982,15880,5795],{"class":3996},[3982,15882,15883,15885,15887],{"class":3984,"line":4883},[3982,15884,8098],{"class":3996},[3982,15886,7538],{"class":4003},[3982,15888,5731],{"class":3996},[3982,15890,15891,15893,15895],{"class":3984,"line":4888},[3982,15892,5824],{"class":3996},[3982,15894,5728],{"class":4003},[3982,15896,5731],{"class":3996},[3982,15898,15899],{"class":3984,"line":4893},[3982,15900,5833],{"class":3996},[3982,15902,15903],{"class":3984,"line":4899},[3982,15904,4852],{"class":3996},[3982,15906,15907],{"class":3984,"line":4905},[3982,15908,4832],{"emptyLinePlaceholder":4831},[3982,15910,15911,15913,15916,15918,15920,15922,15924],{"class":3984,"line":4911},[3982,15912,5236],{"class":3988},[3982,15914,15915],{"class":5239}," styles",[3982,15917,5243],{"class":3996},[3982,15919,7558],{"class":4003},[3982,15921,3823],{"class":3996},[3982,15923,9112],{"class":5253},[3982,15925,15926],{"class":3996},"({\n",[3982,15928,15929,15931],{"class":3984,"line":4916},[3982,15930,8437],{"class":4003},[3982,15932,5342],{"class":3996},[3982,15934,15935,15937,15939],{"class":3984,"line":4921},[3982,15936,8469],{"class":4003},[3982,15938,8472],{"class":4028},[3982,15940,6287],{"class":3996},[3982,15942,15943,15945,15947],{"class":3984,"line":4927},[3982,15944,8585],{"class":4003},[3982,15946,8588],{"class":4028},[3982,15948,6287],{"class":3996},[3982,15950,15951,15953,15955],{"class":3984,"line":4933},[3982,15952,8491],{"class":4003},[3982,15954,8494],{"class":4028},[3982,15956,6287],{"class":3996},[3982,15958,15959,15961,15963],{"class":3984,"line":4938},[3982,15960,8658],{"class":4003},[3982,15962,8564],{"class":6014},[3982,15964,6287],{"class":3996},[3982,15966,15967,15969,15971],{"class":3984,"line":4943},[3982,15968,8668],{"class":4003},[3982,15970,8483],{"class":6014},[3982,15972,6287],{"class":3996},[3982,15974,15975,15977,15979],{"class":3984,"line":4949},[3982,15976,8605],{"class":4003},[3982,15978,8608],{"class":6014},[3982,15980,6287],{"class":3996},[3982,15982,15983],{"class":3984,"line":4954},[3982,15984,8502],{"class":3996},[3982,15986,15987,15990],{"class":3984,"line":4960},[3982,15988,15989],{"class":4003},"  icon:",[3982,15991,5342],{"class":3996},[3982,15993,15994,15996,15999],{"class":3984,"line":4966},[3982,15995,8540],{"class":4003},[3982,15997,15998],{"class":6014}," 18",[3982,16000,6287],{"class":3996},[3982,16002,16003],{"class":3984,"line":4972},[3982,16004,8502],{"class":3996},[3982,16006,16007,16010],{"class":3984,"line":4978},[3982,16008,16009],{"class":4003},"  text:",[3982,16011,5342],{"class":3996},[3982,16013,16014,16016,16018],{"class":3984,"line":4983},[3982,16015,8629],{"class":4003},[3982,16017,8445],{"class":6014},[3982,16019,6287],{"class":3996},[3982,16021,16022,16024,16026],{"class":3984,"line":4989},[3982,16023,8785],{"class":4003},[3982,16025,8516],{"class":4028},[3982,16027,6287],{"class":3996},[3982,16029,16030,16032,16035],{"class":3984,"line":4995},[3982,16031,8540],{"class":4003},[3982,16033,16034],{"class":6014}," 14",[3982,16036,6287],{"class":3996},[3982,16038,16039,16041,16043],{"class":3984,"line":5001},[3982,16040,8551],{"class":4003},[3982,16042,8524],{"class":4028},[3982,16044,6287],{"class":3996},[3982,16046,16047],{"class":3984,"line":5007},[3982,16048,8502],{"class":3996},[3982,16050,16051],{"class":3984,"line":5013},[3982,16052,5422],{"class":3996},[3973,16054,16057],{"className":16055,"code":16056,"language":6479},[7444],"paddingHorizontal: 16,\npaddingVertical: 12,\ngap: 8,\n",[3780,16058,16056],{"__ignoreMap":3978},[3743,16060,16061],{},"},\nicon: {\nfontSize: 18,\n},\ntext: {\nflex: 1,\ncolor: '#fff',\nfontSize: 14,\nfontWeight: '600',\n},\n});",[3973,16063,16066],{"className":16064,"code":16065,"language":6479},[7444],"\n```typescript [src\u002Fcomponents\u002FTripCard.tsx]\nimport { View, Text, Pressable, StyleSheet } from 'react-native';\nimport { useRouter } from 'expo-router';\nimport { Trip } from '..\u002Ftypes';\nimport { useTheme } from '..\u002Fhooks\u002FuseTheme';\n\ntype Props = {\n  trip: Trip;\n};\n\nexport function TripCard({ trip }: Props) {\n  const router = useRouter();\n  const { colors } = useTheme();\n\n  const syncBadge = () => {\n    switch (trip.syncStatus) {\n      case 'pending':\n        return \u003CText style={styles.badgePending}>⏳ Не синхронізовано\u003C\u002FText>;\n      case 'syncing':\n        return \u003CText style={styles.badgeSyncing}>🔄 Відправляється...\u003C\u002FText>;\n      case 'synced':\n        return null; \u002F\u002F Не показуємо badge для synced\n      case 'error':\n        return \u003CText style={styles.badgeError}>❌ Помилка\u003C\u002FText>;\n    }\n  };\n\n  return (\n    \u003CPressable\n      style={[styles.card, { backgroundColor: colors.surface }]}\n      onPress={() => router.push(`\u002Ftrip\u002F${trip.id}`)}\n    >\n      \u003CView style={styles.header}>\n        \u003CText style={[styles.title, { color: colors.text }]}>{trip.title}\u003C\u002FText>\n        {syncBadge()}\n      \u003C\u002FView>\n      \u003CText style={[styles.date, { color: colors.textSecondary }]}>\n        {new Date(trip.startDate).toLocaleDateString('uk-UA')}\n      \u003C\u002FText>\n      {trip.description && (\n        \u003CText\n          style={[styles.description, { color: colors.textSecondary }]}\n          numberOfLines={2}\n        >\n          {trip.description}\n        \u003C\u002FText>\n      )}\n    \u003C\u002FPressable>\n  );\n}\n\nconst styles = StyleSheet.create({\n  card: {\n    padding: 16,\n    borderRadius: 12,\n    marginBottom: 12,\n    elevation: 2,\n    shadowColor: '#000',\n    shadowOffset: { width: 0, height: 1 },\n    shadowOpacity: 0.1,\n    shadowRadius: 2,\n  },\n  header: {\n    flexDirection: 'row',\n    alignItems: 'center',\n    justifyContent: 'space-between',\n    marginBottom: 8,\n  },\n  title: {\n    fontSize: 18,\n    fontWeight: '600',\n    flex: 1,\n  },\n  date: {\n    fontSize: 14,\n    marginBottom: 4,\n  },\n  description: {\n    fontSize: 14,\n    lineHeight: 20,\n  },\n  badgePending: {\n    fontSize: 12,\n    color: '#757575',\n  },\n  badgeSyncing: {\n    fontSize: 12,\n    color: '#2196F3',\n  },\n  badgeError: {\n    fontSize: 12,\n    color: '#F44336',\n  },\n});\n",[3780,16067,16065],{"__ignoreMap":3978},[3973,16069,16071],{"className":3975,"code":16070,"filename":11523,"language":3977,"meta":3978,"style":3978},"import { View, FlatList, StyleSheet } from 'react-native';\nimport { useRouter } from 'expo-router';\nimport { useEffect, useState } from 'react';\nimport { Screen } from '..\u002F..\u002Fsrc\u002Fshared\u002Fui\u002FScreen';\nimport { Button } from '..\u002F..\u002Fsrc\u002Fshared\u002Fui\u002FButton';\nimport { TripCard } from '..\u002F..\u002Fsrc\u002Fcomponents\u002FTripCard';\nimport { OfflineBanner } from '..\u002F..\u002Fsrc\u002Fcomponents\u002FOfflineBanner';\nimport { tripsDb } from '..\u002F..\u002Fsrc\u002Fdb\u002Ftrips';\nimport { useSyncWorker } from '..\u002F..\u002Fsrc\u002Fhooks\u002FuseSyncWorker';\nimport { Trip } from '..\u002F..\u002Fsrc\u002Ftypes';\n\nexport default function TripsScreen() {\n  const router = useRouter();\n  const [trips, setTrips] = useState\u003CTrip[]>([]);\n\n  useSyncWorker(); \u002F\u002F Запустити фонову синхронізацію\n\n  useEffect(() => {\n    loadTrips();\n\n    \u002F\u002F Оновлювати список кожні 2 секунди (щоб бачити зміни syncStatus)\n    const interval = setInterval(loadTrips, 2000);\n    return () => clearInterval(interval);\n  }, []);\n\n  async function loadTrips() {\n    const data = await tripsDb.getAll();\n    setTrips(data);\n  }\n\n  return (\n    \u003CScreen>\n      \u003COfflineBanner \u002F>\n      \u003CFlatList\n        data={trips}\n        keyExtractor={(item) => item.id}\n        renderItem={({ item }) => \u003CTripCard trip={item} \u002F>}\n        contentContainerStyle={styles.list}\n        ListHeaderComponent={\n          \u003CButton\n            title=\"+ Нова поїздка\"\n            onPress={() => router.push('\u002Ftrip\u002Fnew')}\n            variant=\"primary\"\n            style={styles.createButton}\n          \u002F>\n        }\n        stickyHeaderIndices={[0]}\n      \u002F>\n    \u003C\u002FScreen>\n  );\n}\n\nconst styles = StyleSheet.create({\n  list: {\n    padding: 16,\n  },\n  createButton: {\n    marginBottom: 16,\n  },\n});\n",[3780,16072,16073,16097,16114,16134,16152,16170,16188,16206,16223,16240,16257,16261,16274,16287,16311,16315,16324,16328,16338,16345,16349,16354,16375,16391,16395,16399,16410,16428,16440,16444,16448,16454,16462,16471,16477,16487,16497,16517,16529,16537,16544,16554,16568,16576,16581,16586,16590,16595,16599,16604,16608,16612,16616,16620,16627,16635,16639,16646,16655,16659],{"__ignoreMap":3978},[3982,16074,16075,16077,16079,16081,16083,16085,16087,16089,16091,16093,16095],{"class":3984,"line":3985},[3982,16076,5211],{"class":5210},[3982,16078,5444],{"class":3996},[3982,16080,5728],{"class":4003},[3982,16082,3783],{"class":3996},[3982,16084,7548],{"class":4003},[3982,16086,3783],{"class":3996},[3982,16088,7558],{"class":4003},[3982,16090,5455],{"class":3996},[3982,16092,5458],{"class":5210},[3982,16094,7565],{"class":4028},[3982,16096,4043],{"class":3996},[3982,16098,16099,16101,16103,16106,16108,16110,16112],{"class":3984,"line":4000},[3982,16100,5211],{"class":5210},[3982,16102,5444],{"class":3996},[3982,16104,16105],{"class":4003},"useRouter",[3982,16107,5455],{"class":3996},[3982,16109,5458],{"class":5210},[3982,16111,7470],{"class":4028},[3982,16113,4043],{"class":3996},[3982,16115,16116,16118,16120,16122,16124,16126,16128,16130,16132],{"class":3984,"line":4020},[3982,16117,5211],{"class":5210},[3982,16119,5444],{"class":3996},[3982,16121,5447],{"class":4003},[3982,16123,3783],{"class":3996},[3982,16125,5452],{"class":4003},[3982,16127,5455],{"class":3996},[3982,16129,5458],{"class":5210},[3982,16131,5461],{"class":4028},[3982,16133,4043],{"class":3996},[3982,16135,16136,16138,16140,16143,16145,16147,16150],{"class":3984,"line":4046},[3982,16137,5211],{"class":5210},[3982,16139,5444],{"class":3996},[3982,16141,16142],{"class":4003},"Screen",[3982,16144,5455],{"class":3996},[3982,16146,5458],{"class":5210},[3982,16148,16149],{"class":4028}," '..\u002F..\u002Fsrc\u002Fshared\u002Fui\u002FScreen'",[3982,16151,4043],{"class":3996},[3982,16153,16154,16156,16158,16161,16163,16165,16168],{"class":3984,"line":4069},[3982,16155,5211],{"class":5210},[3982,16157,5444],{"class":3996},[3982,16159,16160],{"class":4003},"Button",[3982,16162,5455],{"class":3996},[3982,16164,5458],{"class":5210},[3982,16166,16167],{"class":4028}," '..\u002F..\u002Fsrc\u002Fshared\u002Fui\u002FButton'",[3982,16169,4043],{"class":3996},[3982,16171,16172,16174,16176,16179,16181,16183,16186],{"class":3984,"line":4086},[3982,16173,5211],{"class":5210},[3982,16175,5444],{"class":3996},[3982,16177,16178],{"class":4003},"TripCard",[3982,16180,5455],{"class":3996},[3982,16182,5458],{"class":5210},[3982,16184,16185],{"class":4028}," '..\u002F..\u002Fsrc\u002Fcomponents\u002FTripCard'",[3982,16187,4043],{"class":3996},[3982,16189,16190,16192,16194,16197,16199,16201,16204],{"class":3984,"line":4103},[3982,16191,5211],{"class":5210},[3982,16193,5444],{"class":3996},[3982,16195,16196],{"class":4003},"OfflineBanner",[3982,16198,5455],{"class":3996},[3982,16200,5458],{"class":5210},[3982,16202,16203],{"class":4028}," '..\u002F..\u002Fsrc\u002Fcomponents\u002FOfflineBanner'",[3982,16205,4043],{"class":3996},[3982,16207,16208,16210,16212,16214,16216,16218,16221],{"class":3984,"line":4119},[3982,16209,5211],{"class":5210},[3982,16211,5444],{"class":3996},[3982,16213,14443],{"class":4003},[3982,16215,5455],{"class":3996},[3982,16217,5458],{"class":5210},[3982,16219,16220],{"class":4028}," '..\u002F..\u002Fsrc\u002Fdb\u002Ftrips'",[3982,16222,4043],{"class":3996},[3982,16224,16225,16227,16229,16231,16233,16235,16238],{"class":3984,"line":4135},[3982,16226,5211],{"class":5210},[3982,16228,5444],{"class":3996},[3982,16230,5091],{"class":4003},[3982,16232,5455],{"class":3996},[3982,16234,5458],{"class":5210},[3982,16236,16237],{"class":4028}," '..\u002F..\u002Fsrc\u002Fhooks\u002FuseSyncWorker'",[3982,16239,4043],{"class":3996},[3982,16241,16242,16244,16246,16248,16250,16252,16255],{"class":3984,"line":4859},[3982,16243,5211],{"class":5210},[3982,16245,5444],{"class":3996},[3982,16247,11464],{"class":4003},[3982,16249,5455],{"class":3996},[3982,16251,5458],{"class":5210},[3982,16253,16254],{"class":4028}," '..\u002F..\u002Fsrc\u002Ftypes'",[3982,16256,4043],{"class":3996},[3982,16258,16259],{"class":3984,"line":4865},[3982,16260,4832],{"emptyLinePlaceholder":4831},[3982,16262,16263,16265,16267,16269,16272],{"class":3984,"line":4871},[3982,16264,5484],{"class":5210},[3982,16266,7483],{"class":5210},[3982,16268,5487],{"class":3988},[3982,16270,16271],{"class":5253}," TripsScreen",[3982,16273,5493],{"class":3996},[3982,16275,16276,16278,16281,16283,16285],{"class":3984,"line":4877},[3982,16277,5498],{"class":3988},[3982,16279,16280],{"class":5239}," router",[3982,16282,5243],{"class":3996},[3982,16284,16105],{"class":5253},[3982,16286,5257],{"class":3996},[3982,16288,16289,16291,16293,16295,16297,16300,16302,16304,16306,16308],{"class":3984,"line":4883},[3982,16290,5498],{"class":3988},[3982,16292,5501],{"class":3996},[3982,16294,6379],{"class":5239},[3982,16296,3783],{"class":3996},[3982,16298,16299],{"class":5239},"setTrips",[3982,16301,5512],{"class":3996},[3982,16303,5452],{"class":5253},[3982,16305,9430],{"class":3996},[3982,16307,11464],{"class":3992},[3982,16309,16310],{"class":3996},"[]>([]);\n",[3982,16312,16313],{"class":3984,"line":4888},[3982,16314,4832],{"emptyLinePlaceholder":4831},[3982,16316,16317,16319,16321],{"class":3984,"line":4893},[3982,16318,7727],{"class":5253},[3982,16320,7730],{"class":3996},[3982,16322,16323],{"class":4016},"\u002F\u002F Запустити фонову синхронізацію\n",[3982,16325,16326],{"class":3984,"line":4899},[3982,16327,4832],{"emptyLinePlaceholder":4831},[3982,16329,16330,16332,16334,16336],{"class":3984,"line":4905},[3982,16331,5530],{"class":5253},[3982,16333,5533],{"class":3996},[3982,16335,5536],{"class":3988},[3982,16337,5342],{"class":3996},[3982,16339,16340,16343],{"class":3984,"line":4911},[3982,16341,16342],{"class":5253},"    loadTrips",[3982,16344,5257],{"class":3996},[3982,16346,16347],{"class":3984,"line":4916},[3982,16348,4832],{"emptyLinePlaceholder":4831},[3982,16350,16351],{"class":3984,"line":4921},[3982,16352,16353],{"class":4016},"    \u002F\u002F Оновлювати список кожні 2 секунди (щоб бачити зміни syncStatus)\n",[3982,16355,16356,16358,16360,16362,16364,16366,16369,16371,16373],{"class":3984,"line":4927},[3982,16357,5598],{"class":3988},[3982,16359,10402],{"class":5239},[3982,16361,5243],{"class":3996},[3982,16363,10407],{"class":5253},[3982,16365,5270],{"class":3996},[3982,16367,16368],{"class":4003},"loadTrips",[3982,16370,3783],{"class":3996},[3982,16372,6093],{"class":6014},[3982,16374,5375],{"class":3996},[3982,16376,16377,16379,16381,16383,16385,16387,16389],{"class":3984,"line":4933},[3982,16378,5649],{"class":5210},[3982,16380,9472],{"class":3996},[3982,16382,5536],{"class":3988},[3982,16384,10465],{"class":5253},[3982,16386,5270],{"class":3996},[3982,16388,10470],{"class":4003},[3982,16390,5375],{"class":3996},[3982,16392,16393],{"class":3984,"line":4938},[3982,16394,5658],{"class":3996},[3982,16396,16397],{"class":3984,"line":4943},[3982,16398,4832],{"emptyLinePlaceholder":4831},[3982,16400,16401,16403,16405,16408],{"class":3984,"line":4949},[3982,16402,10495],{"class":3988},[3982,16404,5487],{"class":3988},[3982,16406,16407],{"class":5253}," loadTrips",[3982,16409,5493],{"class":3996},[3982,16411,16412,16414,16416,16418,16420,16422,16424,16426],{"class":3984,"line":4954},[3982,16413,5598],{"class":3988},[3982,16415,15427],{"class":5239},[3982,16417,5243],{"class":3996},[3982,16419,5246],{"class":5210},[3982,16421,12345],{"class":4003},[3982,16423,3823],{"class":3996},[3982,16425,14905],{"class":5253},[3982,16427,5257],{"class":3996},[3982,16429,16430,16433,16435,16438],{"class":3984,"line":4960},[3982,16431,16432],{"class":5253},"    setTrips",[3982,16434,5270],{"class":3996},[3982,16436,16437],{"class":4003},"data",[3982,16439,5375],{"class":3996},[3982,16441,16442],{"class":3984,"line":4966},[3982,16443,5417],{"class":3996},[3982,16445,16446],{"class":3984,"line":4972},[3982,16447,4832],{"emptyLinePlaceholder":4831},[3982,16449,16450,16452],{"class":3984,"line":4978},[3982,16451,5667],{"class":5210},[3982,16453,5720],{"class":3996},[3982,16455,16456,16458,16460],{"class":3984,"line":4983},[3982,16457,5725],{"class":3996},[3982,16459,16142],{"class":3992},[3982,16461,5731],{"class":3996},[3982,16463,16464,16466,16468],{"class":3984,"line":4989},[3982,16465,7915],{"class":3996},[3982,16467,16196],{"class":4003},[3982,16469,16470],{"class":3996}," \u002F>\n",[3982,16472,16473,16475],{"class":3984,"line":4995},[3982,16474,7915],{"class":3996},[3982,16476,8125],{"class":4003},[3982,16478,16479,16481,16483,16485],{"class":3984,"line":5001},[3982,16480,8131],{"class":4003},[3982,16482,8005],{"class":3996},[3982,16484,6379],{"class":4003},[3982,16486,4852],{"class":3996},[3982,16488,16489,16491,16493,16495],{"class":3984,"line":5007},[3982,16490,8143],{"class":4003},[3982,16492,8146],{"class":3996},[3982,16494,5166],{"class":4003},[3982,16496,4852],{"class":3996},[3982,16498,16499,16501,16503,16505,16508,16510,16512,16514],{"class":3984,"line":5013},[3982,16500,8156],{"class":4003},[3982,16502,8159],{"class":3996},[3982,16504,6074],{"class":4003},[3982,16506,16507],{"class":3996}," }) => \u003CTripCard ",[3982,16509,12950],{"class":4003},[3982,16511,8005],{"class":3996},[3982,16513,6074],{"class":4003},[3982,16515,16516],{"class":3996},"} \u002F>}\n",[3982,16518,16519,16522,16524,16527],{"class":3984,"line":5018},[3982,16520,16521],{"class":4003},"        contentContainerStyle",[3982,16523,7825],{"class":3996},[3982,16525,16526],{"class":4003},"list",[3982,16528,4852],{"class":3996},[3982,16530,16531,16534],{"class":3984,"line":5024},[3982,16532,16533],{"class":4003},"        ListHeaderComponent",[3982,16535,16536],{"class":3996},"={\n",[3982,16538,16539,16541],{"class":3984,"line":5030},[3982,16540,7868],{"class":3996},[3982,16542,16543],{"class":4003},"Button\n",[3982,16545,16546,16549,16551],{"class":3984,"line":5035},[3982,16547,16548],{"class":4003},"            title",[3982,16550,5755],{"class":3996},[3982,16552,16553],{"class":4028},"\"+ Нова поїздка\"\n",[3982,16555,16556,16559,16562,16565],{"class":3984,"line":8065},[3982,16557,16558],{"class":4003},"            onPress",[3982,16560,16561],{"class":3996},"={() => router.push(",[3982,16563,16564],{"class":4028},"'\u002Ftrip\u002Fnew'",[3982,16566,16567],{"class":4003},")}\n",[3982,16569,16570,16573],{"class":3984,"line":8086},[3982,16571,16572],{"class":4003},"            variant=",[3982,16574,16575],{"class":4028},"\"primary\"\n",[3982,16577,16578],{"class":3984,"line":8095},[3982,16579,16580],{"class":4003},"            style={styles.createButton}\n",[3982,16582,16583],{"class":3984,"line":8105},[3982,16584,16585],{"class":4003},"          \u002F>\n",[3982,16587,16588],{"class":3984,"line":8110},[3982,16589,10898],{"class":4003},[3982,16591,16592],{"class":3984,"line":8120},[3982,16593,16594],{"class":4003},"        stickyHeaderIndices={[0]}\n",[3982,16596,16597],{"class":3984,"line":8128},[3982,16598,8404],{"class":4003},[3982,16600,16601],{"class":3984,"line":8140},[3982,16602,16603],{"class":4003},"    \u003C\u002FScreen>\n",[3982,16605,16606],{"class":3984,"line":8153},[3982,16607,5833],{"class":4003},[3982,16609,16610],{"class":3984,"line":8167},[3982,16611,4852],{"class":4003},[3982,16613,16614],{"class":3984,"line":8183},[3982,16615,4832],{"emptyLinePlaceholder":4831},[3982,16617,16618],{"class":3984,"line":8208},[3982,16619,8431],{"class":4003},[3982,16621,16622,16625],{"class":3984,"line":8223},[3982,16623,16624],{"class":4003},"  list:",[3982,16626,5342],{"class":3996},[3982,16628,16629,16631,16633],{"class":3984,"line":8241},[3982,16630,8480],{"class":4003},[3982,16632,8564],{"class":6014},[3982,16634,6287],{"class":3996},[3982,16636,16637],{"class":3984,"line":8271},[3982,16638,8502],{"class":3996},[3982,16640,16641,16644],{"class":3984,"line":8277},[3982,16642,16643],{"class":4003},"  createButton:",[3982,16645,5342],{"class":3996},[3982,16647,16648,16651,16653],{"class":3984,"line":8294},[3982,16649,16650],{"class":4003},"    marginBottom:",[3982,16652,8564],{"class":6014},[3982,16654,6287],{"class":3996},[3982,16656,16657],{"class":3984,"line":8308},[3982,16658,8502],{"class":3996},[3982,16660,16661],{"class":3984,"line":8313},[3982,16662,5422],{"class":3996},[3973,16664,16667],{"className":3975,"code":16665,"filename":16666,"language":3977,"meta":3978,"style":3978},"import { View, Text, StyleSheet, ScrollView } from 'react-native';\nimport { useLocalSearchParams, useRouter } from 'expo-router';\nimport { useEffect, useState } from 'react';\nimport { Screen } from '..\u002F..\u002Fsrc\u002Fshared\u002Fui\u002FScreen';\nimport { Button } from '..\u002F..\u002Fsrc\u002Fshared\u002Fui\u002FButton';\nimport { tripsDb } from '..\u002F..\u002Fsrc\u002Fdb\u002Ftrips';\nimport { outboxDb } from '..\u002F..\u002Fsrc\u002Fdb\u002Foutbox';\nimport { Trip } from '..\u002F..\u002Fsrc\u002Ftypes';\nimport { useTheme } from '..\u002F..\u002Fsrc\u002Fhooks\u002FuseTheme';\n\nexport default function TripDetailsScreen() {\n  const { id } = useLocalSearchParams\u003C{ id: string }>();\n  const router = useRouter();\n  const { colors } = useTheme();\n  const [trip, setTrip] = useState\u003CTrip | null>(null);\n\n  useEffect(() => {\n    loadTrip();\n  }, [id]);\n\n  async function loadTrip() {\n    if (!id) return;\n    const data = await tripsDb.getById(id);\n    setTrip(data);\n  }\n\n  async function handleRetry() {\n    if (!trip) return;\n\n    \u002F\u002F Скинути статус на pending\n    await tripsDb.updateSyncStatus(trip.id, 'pending');\n\n    \u002F\u002F Додати в outbox (якщо ще немає)\n    const existing = await outboxDb.getAll();\n    const alreadyQueued = existing.some(\n      item => item.resource === 'trip' && item.payload.id === trip.id\n    );\n\n    if (!alreadyQueued) {\n      await outboxDb.add({\n        operation: 'CREATE',\n        resource: 'trip',\n        payload: { id: trip.id, title: trip.title, startDate: trip.startDate },\n      });\n    }\n\n    \u002F\u002F Оновити UI\n    loadTrip();\n  }\n\n  if (!trip) {\n    return (\n      \u003CScreen>\n        \u003CText style={{ color: colors.text }}>Завантаження...\u003C\u002FText>\n      \u003C\u002FScreen>\n    );\n  }\n\n  return (\n    \u003CScreen>\n      \u003CScrollView contentContainerStyle={styles.content}>\n        \u003CText style={[styles.title, { color: colors.text }]}>{trip.title}\u003C\u002FText>\n        \u003CText style={[styles.date, { color: colors.textSecondary }]}>\n          {new Date(trip.startDate).toLocaleDateString('uk-UA')}\n        \u003C\u002FText>\n\n        {trip.description && (\n          \u003CText style={[styles.description, { color: colors.text }]}>\n            {trip.description}\n          \u003C\u002FText>\n        )}\n\n        {\u002F* Sync status *\u002F}\n        \u003CView style={styles.syncSection}>\n          \u003CText style={[styles.label, { color: colors.textSecondary }]}>\n            Статус синхронізації:\n          \u003C\u002FText>\n          \u003CText style={[styles.status, { color: colors.text }]}>\n            {trip.syncStatus === 'pending' && '⏳ Очікує відправки'}\n            {trip.syncStatus === 'syncing' && '🔄 Відправляється...'}\n            {trip.syncStatus === 'synced' && '✅ Синхронізовано'}\n            {trip.syncStatus === 'error' && '❌ Помилка'}\n          \u003C\u002FText>\n\n          {trip.syncError && (\n            \u003CText style={styles.error}>Помилка: {trip.syncError}\u003C\u002FText>\n          )}\n\n          {trip.syncStatus === 'error' && (\n            \u003CButton\n              title=\"Повторити синхронізацію\"\n              onPress={handleRetry}\n              variant=\"secondary\"\n              style={styles.retryButton}\n            \u002F>\n          )}\n        \u003C\u002FView>\n\n        \u003CButton\n          title=\"← Назад до списку\"\n          onPress={() => router.back()}\n          variant=\"secondary\"\n        \u002F>\n      \u003C\u002FScrollView>\n    \u003C\u002FScreen>\n  );\n}\n\nconst styles = StyleSheet.create({\n  content: {\n    padding: 16,\n  },\n  title: {\n    fontSize: 24,\n    fontWeight: 'bold',\n    marginBottom: 8,\n  },\n  date: {\n    fontSize: 16,\n    marginBottom: 16,\n  },\n  description: {\n    fontSize: 16,\n    lineHeight: 24,\n    marginBottom: 24,\n  },\n  syncSection: {\n    marginBottom: 24,\n    padding: 16,\n    backgroundColor: '#f5f5f5',\n    borderRadius: 8,\n  },\n  label: {\n    fontSize: 14,\n    marginBottom: 4,\n  },\n  status: {\n    fontSize: 16,\n    fontWeight: '600',\n    marginBottom: 8,\n  },\n  error: {\n    fontSize: 14,\n    color: '#F44336',\n    marginBottom: 12,\n  },\n  retryButton: {\n    marginTop: 8,\n  },\n});\n","app\u002Ftrip\u002F[id].tsx",[3780,16668,16669,16698,16719,16739,16755,16771,16787,16804,16820,16838,16842,16855,16879,16891,16906,16937,16941,16951,16958,16966,16970,16981,16995,17018,17029,17033,17037,17048,17062,17066,17071,17095,17099,17104,17123,17142,17180,17184,17188,17199,17212,17221,17230,17270,17274,17278,17282,17287,17293,17297,17301,17311,17317,17325,17360,17368,17372,17376,17380,17386,17394,17410,17423,17428,17433,17438,17442,17447,17452,17457,17462,17466,17470,17480,17485,17490,17495,17504,17517,17522,17527,17532,17537,17541,17545,17550,17566,17571,17575,17588,17595,17605,17617,17627,17639,17644,17648,17656,17660,17666,17676,17684,17693,17697,17705,17713,17717,17721,17725,17741,17748,17756,17760,17766,17774,17782,17790,17794,17801,17809,17817,17821,17828,17836,17845,17853,17857,17864,17872,17880,17888,17896,17900,17907,17915,17924,17928,17935,17943,17951,17959,17963,17970,17978,17987,17996,18001,18008,18018,18023],{"__ignoreMap":3978},[3982,16670,16671,16673,16675,16677,16679,16681,16683,16685,16687,16690,16692,16694,16696],{"class":3984,"line":3985},[3982,16672,5211],{"class":5210},[3982,16674,5444],{"class":3996},[3982,16676,5728],{"class":4003},[3982,16678,3783],{"class":3996},[3982,16680,7538],{"class":4003},[3982,16682,3783],{"class":3996},[3982,16684,7558],{"class":4003},[3982,16686,3783],{"class":3996},[3982,16688,16689],{"class":4003},"ScrollView",[3982,16691,5455],{"class":3996},[3982,16693,5458],{"class":5210},[3982,16695,7565],{"class":4028},[3982,16697,4043],{"class":3996},[3982,16699,16700,16702,16704,16707,16709,16711,16713,16715,16717],{"class":3984,"line":4000},[3982,16701,5211],{"class":5210},[3982,16703,5444],{"class":3996},[3982,16705,16706],{"class":4003},"useLocalSearchParams",[3982,16708,3783],{"class":3996},[3982,16710,16105],{"class":4003},[3982,16712,5455],{"class":3996},[3982,16714,5458],{"class":5210},[3982,16716,7470],{"class":4028},[3982,16718,4043],{"class":3996},[3982,16720,16721,16723,16725,16727,16729,16731,16733,16735,16737],{"class":3984,"line":4020},[3982,16722,5211],{"class":5210},[3982,16724,5444],{"class":3996},[3982,16726,5447],{"class":4003},[3982,16728,3783],{"class":3996},[3982,16730,5452],{"class":4003},[3982,16732,5455],{"class":3996},[3982,16734,5458],{"class":5210},[3982,16736,5461],{"class":4028},[3982,16738,4043],{"class":3996},[3982,16740,16741,16743,16745,16747,16749,16751,16753],{"class":3984,"line":4046},[3982,16742,5211],{"class":5210},[3982,16744,5444],{"class":3996},[3982,16746,16142],{"class":4003},[3982,16748,5455],{"class":3996},[3982,16750,5458],{"class":5210},[3982,16752,16149],{"class":4028},[3982,16754,4043],{"class":3996},[3982,16756,16757,16759,16761,16763,16765,16767,16769],{"class":3984,"line":4069},[3982,16758,5211],{"class":5210},[3982,16760,5444],{"class":3996},[3982,16762,16160],{"class":4003},[3982,16764,5455],{"class":3996},[3982,16766,5458],{"class":5210},[3982,16768,16167],{"class":4028},[3982,16770,4043],{"class":3996},[3982,16772,16773,16775,16777,16779,16781,16783,16785],{"class":3984,"line":4086},[3982,16774,5211],{"class":5210},[3982,16776,5444],{"class":3996},[3982,16778,14443],{"class":4003},[3982,16780,5455],{"class":3996},[3982,16782,5458],{"class":5210},[3982,16784,16220],{"class":4028},[3982,16786,4043],{"class":3996},[3982,16788,16789,16791,16793,16795,16797,16799,16802],{"class":3984,"line":4103},[3982,16790,5211],{"class":5210},[3982,16792,5444],{"class":3996},[3982,16794,14438],{"class":4003},[3982,16796,5455],{"class":3996},[3982,16798,5458],{"class":5210},[3982,16800,16801],{"class":4028}," '..\u002F..\u002Fsrc\u002Fdb\u002Foutbox'",[3982,16803,4043],{"class":3996},[3982,16805,16806,16808,16810,16812,16814,16816,16818],{"class":3984,"line":4119},[3982,16807,5211],{"class":5210},[3982,16809,5444],{"class":3996},[3982,16811,11464],{"class":4003},[3982,16813,5455],{"class":3996},[3982,16815,5458],{"class":5210},[3982,16817,16254],{"class":4028},[3982,16819,4043],{"class":3996},[3982,16821,16822,16824,16826,16829,16831,16833,16836],{"class":3984,"line":4135},[3982,16823,5211],{"class":5210},[3982,16825,5444],{"class":3996},[3982,16827,16828],{"class":4003},"useTheme",[3982,16830,5455],{"class":3996},[3982,16832,5458],{"class":5210},[3982,16834,16835],{"class":4028}," '..\u002F..\u002Fsrc\u002Fhooks\u002FuseTheme'",[3982,16837,4043],{"class":3996},[3982,16839,16840],{"class":3984,"line":4859},[3982,16841,4832],{"emptyLinePlaceholder":4831},[3982,16843,16844,16846,16848,16850,16853],{"class":3984,"line":4865},[3982,16845,5484],{"class":5210},[3982,16847,7483],{"class":5210},[3982,16849,5487],{"class":3988},[3982,16851,16852],{"class":5253}," TripDetailsScreen",[3982,16854,5493],{"class":3996},[3982,16856,16857,16859,16861,16863,16865,16867,16870,16872,16874,16876],{"class":3984,"line":4871},[3982,16858,5498],{"class":3988},[3982,16860,5444],{"class":3996},[3982,16862,5166],{"class":5239},[3982,16864,7702],{"class":3996},[3982,16866,16706],{"class":5253},[3982,16868,16869],{"class":3996},"\u003C{ ",[3982,16871,5166],{"class":4003},[3982,16873,4007],{"class":3996},[3982,16875,4010],{"class":3992},[3982,16877,16878],{"class":3996}," }>();\n",[3982,16880,16881,16883,16885,16887,16889],{"class":3984,"line":4877},[3982,16882,5498],{"class":3988},[3982,16884,16280],{"class":5239},[3982,16886,5243],{"class":3996},[3982,16888,16105],{"class":5253},[3982,16890,5257],{"class":3996},[3982,16892,16893,16895,16897,16900,16902,16904],{"class":3984,"line":4883},[3982,16894,5498],{"class":3988},[3982,16896,5444],{"class":3996},[3982,16898,16899],{"class":5239},"colors",[3982,16901,7702],{"class":3996},[3982,16903,16828],{"class":5253},[3982,16905,5257],{"class":3996},[3982,16907,16908,16910,16912,16914,16916,16919,16921,16923,16925,16927,16929,16931,16933,16935],{"class":3984,"line":4888},[3982,16909,5498],{"class":3988},[3982,16911,5501],{"class":3996},[3982,16913,12950],{"class":5239},[3982,16915,3783],{"class":3996},[3982,16917,16918],{"class":5239},"setTrip",[3982,16920,5512],{"class":3996},[3982,16922,5452],{"class":5253},[3982,16924,9430],{"class":3996},[3982,16926,11464],{"class":3992},[3982,16928,4032],{"class":3996},[3982,16930,12695],{"class":3992},[3982,16932,12417],{"class":3996},[3982,16934,12695],{"class":3988},[3982,16936,5375],{"class":3996},[3982,16938,16939],{"class":3984,"line":4893},[3982,16940,4832],{"emptyLinePlaceholder":4831},[3982,16942,16943,16945,16947,16949],{"class":3984,"line":4899},[3982,16944,5530],{"class":5253},[3982,16946,5533],{"class":3996},[3982,16948,5536],{"class":3988},[3982,16950,5342],{"class":3996},[3982,16952,16953,16956],{"class":3984,"line":4905},[3982,16954,16955],{"class":5253},"    loadTrip",[3982,16957,5257],{"class":3996},[3982,16959,16960,16962,16964],{"class":3984,"line":4911},[3982,16961,10477],{"class":3996},[3982,16963,5166],{"class":4003},[3982,16965,10486],{"class":3996},[3982,16967,16968],{"class":3984,"line":4916},[3982,16969,4832],{"emptyLinePlaceholder":4831},[3982,16971,16972,16974,16976,16979],{"class":3984,"line":4921},[3982,16973,10495],{"class":3988},[3982,16975,5487],{"class":3988},[3982,16977,16978],{"class":5253}," loadTrip",[3982,16980,5493],{"class":3996},[3982,16982,16983,16985,16987,16989,16991,16993],{"class":3984,"line":4927},[3982,16984,6324],{"class":5210},[3982,16986,10382],{"class":3996},[3982,16988,5166],{"class":4003},[3982,16990,9317],{"class":3996},[3982,16992,10389],{"class":5210},[3982,16994,4043],{"class":3996},[3982,16996,16997,16999,17001,17003,17005,17007,17009,17012,17014,17016],{"class":3984,"line":4933},[3982,16998,5598],{"class":3988},[3982,17000,15427],{"class":5239},[3982,17002,5243],{"class":3996},[3982,17004,5246],{"class":5210},[3982,17006,12345],{"class":4003},[3982,17008,3823],{"class":3996},[3982,17010,17011],{"class":5253},"getById",[3982,17013,5270],{"class":3996},[3982,17015,5166],{"class":4003},[3982,17017,5375],{"class":3996},[3982,17019,17020,17023,17025,17027],{"class":3984,"line":4938},[3982,17021,17022],{"class":5253},"    setTrip",[3982,17024,5270],{"class":3996},[3982,17026,16437],{"class":4003},[3982,17028,5375],{"class":3996},[3982,17030,17031],{"class":3984,"line":4943},[3982,17032,5417],{"class":3996},[3982,17034,17035],{"class":3984,"line":4949},[3982,17036,4832],{"emptyLinePlaceholder":4831},[3982,17038,17039,17041,17043,17046],{"class":3984,"line":4954},[3982,17040,10495],{"class":3988},[3982,17042,5487],{"class":3988},[3982,17044,17045],{"class":5253}," handleRetry",[3982,17047,5493],{"class":3996},[3982,17049,17050,17052,17054,17056,17058,17060],{"class":3984,"line":4960},[3982,17051,6324],{"class":5210},[3982,17053,10382],{"class":3996},[3982,17055,12950],{"class":4003},[3982,17057,9317],{"class":3996},[3982,17059,10389],{"class":5210},[3982,17061,4043],{"class":3996},[3982,17063,17064],{"class":3984,"line":4966},[3982,17065,4832],{"emptyLinePlaceholder":4831},[3982,17067,17068],{"class":3984,"line":4972},[3982,17069,17070],{"class":4016},"    \u002F\u002F Скинути статус на pending\n",[3982,17072,17073,17075,17077,17079,17081,17083,17085,17087,17089,17091,17093],{"class":3984,"line":4978},[3982,17074,6515],{"class":5210},[3982,17076,12345],{"class":4003},[3982,17078,3823],{"class":3996},[3982,17080,15126],{"class":5253},[3982,17082,5270],{"class":3996},[3982,17084,12950],{"class":4003},[3982,17086,3823],{"class":3996},[3982,17088,5166],{"class":4003},[3982,17090,3783],{"class":3996},[3982,17092,4265],{"class":4028},[3982,17094,5375],{"class":3996},[3982,17096,17097],{"class":3984,"line":4983},[3982,17098,4832],{"emptyLinePlaceholder":4831},[3982,17100,17101],{"class":3984,"line":4989},[3982,17102,17103],{"class":4016},"    \u002F\u002F Додати в outbox (якщо ще немає)\n",[3982,17105,17106,17108,17111,17113,17115,17117,17119,17121],{"class":3984,"line":4995},[3982,17107,5598],{"class":3988},[3982,17109,17110],{"class":5239}," existing",[3982,17112,5243],{"class":3996},[3982,17114,5246],{"class":5210},[3982,17116,13616],{"class":4003},[3982,17118,3823],{"class":3996},[3982,17120,14905],{"class":5253},[3982,17122,5257],{"class":3996},[3982,17124,17125,17127,17130,17132,17135,17137,17140],{"class":3984,"line":5001},[3982,17126,5598],{"class":3988},[3982,17128,17129],{"class":5239}," alreadyQueued",[3982,17131,5243],{"class":3996},[3982,17133,17134],{"class":4003},"existing",[3982,17136,3823],{"class":3996},[3982,17138,17139],{"class":5253},"some",[3982,17141,5994],{"class":3996},[3982,17143,17144,17147,17149,17151,17153,17155,17157,17159,17162,17164,17166,17168,17170,17172,17174,17176,17178],{"class":3984,"line":5007},[3982,17145,17146],{"class":4003},"      item",[3982,17148,5339],{"class":3988},[3982,17150,6262],{"class":4003},[3982,17152,3823],{"class":3996},[3982,17154,6245],{"class":4003},[3982,17156,6270],{"class":3996},[3982,17158,4054],{"class":4028},[3982,17160,17161],{"class":3996}," && ",[3982,17163,6074],{"class":4003},[3982,17165,3823],{"class":3996},[3982,17167,6309],{"class":4003},[3982,17169,3823],{"class":3996},[3982,17171,5166],{"class":4003},[3982,17173,6270],{"class":3996},[3982,17175,12950],{"class":4003},[3982,17177,3823],{"class":3996},[3982,17179,9815],{"class":4003},[3982,17181,17182],{"class":3984,"line":5013},[3982,17183,9868],{"class":3996},[3982,17185,17186],{"class":3984,"line":5018},[3982,17187,4832],{"emptyLinePlaceholder":4831},[3982,17189,17190,17192,17194,17197],{"class":3984,"line":5024},[3982,17191,6324],{"class":5210},[3982,17193,10382],{"class":3996},[3982,17195,17196],{"class":4003},"alreadyQueued",[3982,17198,5358],{"class":3996},[3982,17200,17201,17203,17205,17207,17210],{"class":3984,"line":5030},[3982,17202,6346],{"class":5210},[3982,17204,13616],{"class":4003},[3982,17206,3823],{"class":3996},[3982,17208,17209],{"class":5253},"add",[3982,17211,15926],{"class":3996},[3982,17213,17214,17217,17219],{"class":3984,"line":5035},[3982,17215,17216],{"class":4003},"        operation:",[3982,17218,13790],{"class":4028},[3982,17220,6287],{"class":3996},[3982,17222,17223,17226,17228],{"class":3984,"line":8065},[3982,17224,17225],{"class":4003},"        resource:",[3982,17227,13816],{"class":4028},[3982,17229,6287],{"class":3996},[3982,17231,17232,17235,17237,17239,17241,17243,17245,17247,17250,17252,17254,17256,17258,17261,17263,17265,17268],{"class":3984,"line":8086},[3982,17233,17234],{"class":4003},"        payload:",[3982,17236,5444],{"class":3996},[3982,17238,9841],{"class":4003},[3982,17240,13301],{"class":4003},[3982,17242,3823],{"class":3996},[3982,17244,5166],{"class":4003},[3982,17246,3783],{"class":3996},[3982,17248,17249],{"class":4003},"title:",[3982,17251,13301],{"class":4003},[3982,17253,3823],{"class":3996},[3982,17255,7924],{"class":4003},[3982,17257,3783],{"class":3996},[3982,17259,17260],{"class":4003},"startDate:",[3982,17262,13301],{"class":4003},[3982,17264,3823],{"class":3996},[3982,17266,17267],{"class":4003},"startDate",[3982,17269,6978],{"class":3996},[3982,17271,17272],{"class":3984,"line":8095},[3982,17273,6487],{"class":3996},[3982,17275,17276],{"class":3984,"line":8105},[3982,17277,6492],{"class":3996},[3982,17279,17280],{"class":3984,"line":8110},[3982,17281,4832],{"emptyLinePlaceholder":4831},[3982,17283,17284],{"class":3984,"line":8120},[3982,17285,17286],{"class":4016},"    \u002F\u002F Оновити UI\n",[3982,17288,17289,17291],{"class":3984,"line":8128},[3982,17290,16955],{"class":5253},[3982,17292,5257],{"class":3996},[3982,17294,17295],{"class":3984,"line":8140},[3982,17296,5417],{"class":3996},[3982,17298,17299],{"class":3984,"line":8153},[3982,17300,4832],{"emptyLinePlaceholder":4831},[3982,17302,17303,17305,17307,17309],{"class":3984,"line":8167},[3982,17304,5347],{"class":5210},[3982,17306,10382],{"class":3996},[3982,17308,12950],{"class":4003},[3982,17310,5358],{"class":3996},[3982,17312,17313,17315],{"class":3984,"line":8183},[3982,17314,5649],{"class":5210},[3982,17316,5720],{"class":3996},[3982,17318,17319,17321,17323],{"class":3984,"line":8208},[3982,17320,7915],{"class":3996},[3982,17322,16142],{"class":3992},[3982,17324,5731],{"class":3996},[3982,17326,17327,17329,17331,17333,17335,17339,17341,17343,17345,17347,17350,17353,17356,17358],{"class":3984,"line":8223},[3982,17328,5746],{"class":3996},[3982,17330,7538],{"class":4003},[3982,17332,7822],{"class":4003},[3982,17334,7505],{"class":3996},[3982,17336,17338],{"class":17337},"s5IvJ","color",[3982,17340,4007],{"class":3996},[3982,17342,16899],{"class":4003},[3982,17344,3823],{"class":3996},[3982,17346,6479],{"class":4003},[3982,17348,17349],{"class":3996}," }}>",[3982,17351,17352],{"class":4003},"Завантаження",[3982,17354,17355],{"class":3996},"...\u003C\u002F",[3982,17357,7538],{"class":4003},[3982,17359,5731],{"class":3996},[3982,17361,17362,17364,17366],{"class":3984,"line":8241},[3982,17363,8098],{"class":3996},[3982,17365,16142],{"class":4003},[3982,17367,5731],{"class":3996},[3982,17369,17370],{"class":3984,"line":8271},[3982,17371,9868],{"class":3996},[3982,17373,17374],{"class":3984,"line":8277},[3982,17375,5417],{"class":3996},[3982,17377,17378],{"class":3984,"line":8294},[3982,17379,4832],{"emptyLinePlaceholder":4831},[3982,17381,17382,17384],{"class":3984,"line":8308},[3982,17383,5667],{"class":5210},[3982,17385,5720],{"class":3996},[3982,17387,17388,17390,17392],{"class":3984,"line":8313},[3982,17389,5725],{"class":3996},[3982,17391,16142],{"class":3992},[3982,17393,5731],{"class":3996},[3982,17395,17396,17398,17400,17403,17405,17408],{"class":3984,"line":8319},[3982,17397,7915],{"class":3996},[3982,17399,16689],{"class":4003},[3982,17401,17402],{"class":4003}," contentContainerStyle",[3982,17404,7825],{"class":3996},[3982,17406,17407],{"class":4003},"content",[3982,17409,7831],{"class":3996},[3982,17411,17412,17414,17416,17418,17420],{"class":3984,"line":8325},[3982,17413,5746],{"class":3996},[3982,17415,7538],{"class":4003},[3982,17417,7822],{"class":4003},[3982,17419,8005],{"class":3996},[3982,17421,17422],{"class":4003},"[styles.title, { color: colors.text }]}>{trip.title}\u003C\u002FText>\n",[3982,17424,17425],{"class":3984,"line":8330},[3982,17426,17427],{"class":4003},"        \u003CText style={[styles.date, { color: colors.textSecondary }]}>\n",[3982,17429,17430],{"class":3984,"line":8336},[3982,17431,17432],{"class":4003},"          {new Date(trip.startDate).toLocaleDateString('uk-UA')}\n",[3982,17434,17435],{"class":3984,"line":8342},[3982,17436,17437],{"class":4003},"        \u003C\u002FText>\n",[3982,17439,17440],{"class":3984,"line":8348},[3982,17441,4832],{"emptyLinePlaceholder":4831},[3982,17443,17444],{"class":3984,"line":8354},[3982,17445,17446],{"class":4003},"        {trip.description && (\n",[3982,17448,17449],{"class":3984,"line":8360},[3982,17450,17451],{"class":4003},"          \u003CText style={[styles.description, { color: colors.text }]}>\n",[3982,17453,17454],{"class":3984,"line":8366},[3982,17455,17456],{"class":4003},"            {trip.description}\n",[3982,17458,17459],{"class":3984,"line":8372},[3982,17460,17461],{"class":4003},"          \u003C\u002FText>\n",[3982,17463,17464],{"class":3984,"line":8377},[3982,17465,8392],{"class":4003},[3982,17467,17468],{"class":3984,"line":8383},[3982,17469,4832],{"emptyLinePlaceholder":4831},[3982,17471,17472,17475,17478],{"class":3984,"line":8389},[3982,17473,17474],{"class":4003},"        {",[3982,17476,17477],{"class":4016},"\u002F* Sync status *\u002F",[3982,17479,4852],{"class":4003},[3982,17481,17482],{"class":3984,"line":8395},[3982,17483,17484],{"class":4003},"        \u003CView style={styles.syncSection}>\n",[3982,17486,17487],{"class":3984,"line":8401},[3982,17488,17489],{"class":4003},"          \u003CText style={[styles.label, { color: colors.textSecondary }]}>\n",[3982,17491,17492],{"class":3984,"line":8407},[3982,17493,17494],{"class":4003},"            Статус синхронізації:\n",[3982,17496,17497,17500,17502],{"class":3984,"line":8413},[3982,17498,17499],{"class":3996},"          \u003C\u002F",[3982,17501,7538],{"class":4003},[3982,17503,5731],{"class":3996},[3982,17505,17506,17508,17510,17512,17514],{"class":3984,"line":8418},[3982,17507,7868],{"class":3996},[3982,17509,7538],{"class":4003},[3982,17511,7822],{"class":4003},[3982,17513,8005],{"class":3996},[3982,17515,17516],{"class":4003},"[styles.status, { color: colors.text }]}>\n",[3982,17518,17519],{"class":3984,"line":8423},[3982,17520,17521],{"class":4003},"            {trip.syncStatus === 'pending' && '⏳ Очікує відправки'}\n",[3982,17523,17524],{"class":3984,"line":8428},[3982,17525,17526],{"class":4003},"            {trip.syncStatus === 'syncing' && '🔄 Відправляється...'}\n",[3982,17528,17529],{"class":3984,"line":8434},[3982,17530,17531],{"class":4003},"            {trip.syncStatus === 'synced' && '✅ Синхронізовано'}\n",[3982,17533,17534],{"class":3984,"line":8458},[3982,17535,17536],{"class":4003},"            {trip.syncStatus === 'error' && '❌ Помилка'}\n",[3982,17538,17539],{"class":3984,"line":8466},[3982,17540,17461],{"class":4003},[3982,17542,17543],{"class":3984,"line":8477},[3982,17544,4832],{"emptyLinePlaceholder":4831},[3982,17546,17547],{"class":3984,"line":8488},[3982,17548,17549],{"class":4003},"          {trip.syncError && (\n",[3982,17551,17552,17555,17558,17560,17562,17564],{"class":3984,"line":8499},[3982,17553,17554],{"class":4003},"            \u003CText style={styles.error}>Помилка:",[3982,17556,17557],{"class":3996}," {trip.",[3982,17559,3822],{"class":4003},[3982,17561,8201],{"class":3996},[3982,17563,7538],{"class":4003},[3982,17565,5731],{"class":3996},[3982,17567,17568],{"class":3984,"line":8505},[3982,17569,17570],{"class":3996},"          )}\n",[3982,17572,17573],{"class":3984,"line":8529},[3982,17574,4832],{"emptyLinePlaceholder":4831},[3982,17576,17577,17580,17582,17584,17586],{"class":3984,"line":8537},[3982,17578,17579],{"class":3996},"          {trip.",[3982,17581,3818],{"class":4003},[3982,17583,6270],{"class":3996},[3982,17585,4295],{"class":4028},[3982,17587,5741],{"class":3996},[3982,17589,17590,17593],{"class":3984,"line":8548},[3982,17591,17592],{"class":3996},"            \u003C",[3982,17594,16543],{"class":4003},[3982,17596,17597,17600,17602],{"class":3984,"line":8559},[3982,17598,17599],{"class":4003},"              title",[3982,17601,5755],{"class":3996},[3982,17603,17604],{"class":4028},"\"Повторити синхронізацію\"\n",[3982,17606,17607,17610,17612,17615],{"class":3984,"line":8569},[3982,17608,17609],{"class":4003},"              onPress",[3982,17611,8005],{"class":3996},[3982,17613,17614],{"class":4003},"handleRetry",[3982,17616,4852],{"class":3996},[3982,17618,17619,17622,17624],{"class":3984,"line":8574},[3982,17620,17621],{"class":4003},"              variant",[3982,17623,5755],{"class":3996},[3982,17625,17626],{"class":4028},"\"secondary\"\n",[3982,17628,17629,17632,17634,17637],{"class":3984,"line":8582},[3982,17630,17631],{"class":4003},"              style",[3982,17633,7825],{"class":3996},[3982,17635,17636],{"class":4003},"retryButton",[3982,17638,4852],{"class":3996},[3982,17640,17641],{"class":3984,"line":8593},[3982,17642,17643],{"class":3996},"            \u002F>\n",[3982,17645,17646],{"class":3984,"line":8602},[3982,17647,17570],{"class":3996},[3982,17649,17650,17652,17654],{"class":3984,"line":8613},[3982,17651,5800],{"class":3996},[3982,17653,5728],{"class":4003},[3982,17655,5731],{"class":3996},[3982,17657,17658],{"class":3984,"line":8618},[3982,17659,4832],{"emptyLinePlaceholder":4831},[3982,17661,17662,17664],{"class":3984,"line":8626},[3982,17663,5746],{"class":3996},[3982,17665,16543],{"class":4003},[3982,17667,17668,17671,17673],{"class":3984,"line":8636},[3982,17669,17670],{"class":4003},"          title",[3982,17672,5755],{"class":3996},[3982,17674,17675],{"class":4028},"\"← Назад до списку\"\n",[3982,17677,17678,17681],{"class":3984,"line":8645},[3982,17679,17680],{"class":4003},"          onPress",[3982,17682,17683],{"class":3996},"={() => router.back()}\n",[3982,17685,17686,17689,17691],{"class":3984,"line":8655},[3982,17687,17688],{"class":4003},"          variant",[3982,17690,5755],{"class":3996},[3982,17692,17626],{"class":4028},[3982,17694,17695],{"class":3984,"line":8665},[3982,17696,8037],{"class":3996},[3982,17698,17699,17701,17703],{"class":3984,"line":8676},[3982,17700,8098],{"class":3996},[3982,17702,16689],{"class":4003},[3982,17704,5731],{"class":3996},[3982,17706,17707,17709,17711],{"class":3984,"line":8686},[3982,17708,5824],{"class":3996},[3982,17710,16142],{"class":4003},[3982,17712,5731],{"class":3996},[3982,17714,17715],{"class":3984,"line":8697},[3982,17716,5833],{"class":3996},[3982,17718,17719],{"class":3984,"line":8702},[3982,17720,4852],{"class":3996},[3982,17722,17723],{"class":3984,"line":8710},[3982,17724,4832],{"emptyLinePlaceholder":4831},[3982,17726,17727,17729,17731,17733,17735,17737,17739],{"class":3984,"line":8720},[3982,17728,5236],{"class":4003},[3982,17730,15915],{"class":4003},[3982,17732,5243],{"class":3996},[3982,17734,7558],{"class":4003},[3982,17736,3823],{"class":3996},[3982,17738,9112],{"class":5253},[3982,17740,15926],{"class":3996},[3982,17742,17743,17746],{"class":3984,"line":8731},[3982,17744,17745],{"class":4003},"  content:",[3982,17747,5342],{"class":3996},[3982,17749,17750,17752,17754],{"class":3984,"line":8741},[3982,17751,8480],{"class":4003},[3982,17753,8564],{"class":6014},[3982,17755,6287],{"class":3996},[3982,17757,17758],{"class":3984,"line":8750},[3982,17759,8502],{"class":3996},[3982,17761,17762,17764],{"class":3984,"line":8759},[3982,17763,8532],{"class":4003},[3982,17765,5342],{"class":3996},[3982,17767,17768,17770,17772],{"class":3984,"line":8769},[3982,17769,8540],{"class":4003},[3982,17771,8543],{"class":6014},[3982,17773,6287],{"class":3996},[3982,17775,17776,17778,17780],{"class":3984,"line":8774},[3982,17777,8551],{"class":4003},[3982,17779,8554],{"class":4028},[3982,17781,6287],{"class":3996},[3982,17783,17784,17786,17788],{"class":3984,"line":8782},[3982,17785,16650],{"class":4003},[3982,17787,8608],{"class":6014},[3982,17789,6287],{"class":3996},[3982,17791,17792],{"class":3984,"line":8792},[3982,17793,8502],{"class":3996},[3982,17795,17796,17799],{"class":3984,"line":8801},[3982,17797,17798],{"class":4003},"  date:",[3982,17800,5342],{"class":3996},[3982,17802,17803,17805,17807],{"class":3984,"line":8810},[3982,17804,8540],{"class":4003},[3982,17806,8564],{"class":6014},[3982,17808,6287],{"class":3996},[3982,17810,17811,17813,17815],{"class":3984,"line":8815},[3982,17812,16650],{"class":4003},[3982,17814,8564],{"class":6014},[3982,17816,6287],{"class":3996},[3982,17818,17819],{"class":3984,"line":8837},[3982,17820,8502],{"class":3996},[3982,17822,17823,17826],{"class":3984,"line":8845},[3982,17824,17825],{"class":4003},"  description:",[3982,17827,5342],{"class":3996},[3982,17829,17830,17832,17834],{"class":3984,"line":8854},[3982,17831,8540],{"class":4003},[3982,17833,8564],{"class":6014},[3982,17835,6287],{"class":3996},[3982,17837,17838,17841,17843],{"class":3984,"line":8863},[3982,17839,17840],{"class":4003},"    lineHeight:",[3982,17842,8543],{"class":6014},[3982,17844,6287],{"class":3996},[3982,17846,17847,17849,17851],{"class":3984,"line":8872},[3982,17848,16650],{"class":4003},[3982,17850,8543],{"class":6014},[3982,17852,6287],{"class":3996},[3982,17854,17855],{"class":3984,"line":8881},[3982,17856,8502],{"class":3996},[3982,17858,17859,17862],{"class":3984,"line":8891},[3982,17860,17861],{"class":4003},"  syncSection:",[3982,17863,5342],{"class":3996},[3982,17865,17866,17868,17870],{"class":3984,"line":8896},[3982,17867,16650],{"class":4003},[3982,17869,8543],{"class":6014},[3982,17871,6287],{"class":3996},[3982,17873,17874,17876,17878],{"class":3984,"line":8918},[3982,17875,8480],{"class":4003},[3982,17877,8564],{"class":6014},[3982,17879,6287],{"class":3996},[3982,17881,17882,17884,17886],{"class":3984,"line":8946},[3982,17883,8469],{"class":4003},[3982,17885,8453],{"class":4028},[3982,17887,6287],{"class":3996},[3982,17889,17890,17892,17894],{"class":3984,"line":8954},[3982,17891,8648],{"class":4003},[3982,17893,8608],{"class":6014},[3982,17895,6287],{"class":3996},[3982,17897,17898],{"class":3984,"line":8963},[3982,17899,8502],{"class":3996},[3982,17901,17902,17905],{"class":3984,"line":8973},[3982,17903,17904],{"class":4003},"  label:",[3982,17906,5342],{"class":3996},[3982,17908,17909,17911,17913],{"class":3984,"line":8978},[3982,17910,8540],{"class":4003},[3982,17912,16034],{"class":6014},[3982,17914,6287],{"class":3996},[3982,17916,17917,17919,17922],{"class":3984,"line":8992},[3982,17918,16650],{"class":4003},[3982,17920,17921],{"class":6014}," 4",[3982,17923,6287],{"class":3996},[3982,17925,17926],{"class":3984,"line":9007},[3982,17927,8502],{"class":3996},[3982,17929,17930,17933],{"class":3984,"line":9022},[3982,17931,17932],{"class":4003},"  status:",[3982,17934,5342],{"class":3996},[3982,17936,17937,17939,17941],{"class":3984,"line":9048},[3982,17938,8540],{"class":4003},[3982,17940,8564],{"class":6014},[3982,17942,6287],{"class":3996},[3982,17944,17945,17947,17949],{"class":3984,"line":9056},[3982,17946,8551],{"class":4003},[3982,17948,8524],{"class":4028},[3982,17950,6287],{"class":3996},[3982,17952,17953,17955,17957],{"class":3984,"line":9065},[3982,17954,16650],{"class":4003},[3982,17956,8608],{"class":6014},[3982,17958,6287],{"class":3996},[3982,17960,17961],{"class":3984,"line":9074},[3982,17962,8502],{"class":3996},[3982,17964,17965,17968],{"class":3984,"line":9083},[3982,17966,17967],{"class":4003},"  error:",[3982,17969,5342],{"class":3996},[3982,17971,17972,17974,17976],{"class":3984,"line":9088},[3982,17973,8540],{"class":4003},[3982,17975,16034],{"class":6014},[3982,17977,6287],{"class":3996},[3982,17979,17981,17983,17985],{"class":3984,"line":17980},144,[3982,17982,8785],{"class":4003},[3982,17984,9017],{"class":4028},[3982,17986,6287],{"class":3996},[3982,17988,17990,17992,17994],{"class":3984,"line":17989},145,[3982,17991,16650],{"class":4003},[3982,17993,8483],{"class":6014},[3982,17995,6287],{"class":3996},[3982,17997,17999],{"class":3984,"line":17998},146,[3982,18000,8502],{"class":3996},[3982,18002,18004,18006],{"class":3984,"line":18003},147,[3982,18005,9051],{"class":4003},[3982,18007,5342],{"class":3996},[3982,18009,18011,18014,18016],{"class":3984,"line":18010},148,[3982,18012,18013],{"class":4003},"    marginTop:",[3982,18015,8608],{"class":6014},[3982,18017,6287],{"class":3996},[3982,18019,18021],{"class":3984,"line":18020},149,[3982,18022,8502],{"class":3996},[3982,18024,18026],{"class":3984,"line":18025},150,[3982,18027,5422],{"class":3996},[3973,18029,18032],{"className":3975,"code":18030,"filename":18031,"language":3977,"meta":3978,"style":3978},"import { View, TextInput, StyleSheet } from 'react-native';\nimport { useRouter } from 'expo-router';\nimport { useState } from 'react';\nimport { Screen } from '..\u002F..\u002Fsrc\u002Fshared\u002Fui\u002FScreen';\nimport { Button } from '..\u002F..\u002Fsrc\u002Fshared\u002Fui\u002FButton';\nimport { AppText } from '..\u002F..\u002Fsrc\u002Fshared\u002Fui\u002FAppText';\nimport { tripsDb } from '..\u002F..\u002Fsrc\u002Fdb\u002Ftrips';\nimport { outboxDb } from '..\u002F..\u002Fsrc\u002Fdb\u002Foutbox';\nimport { useTheme } from '..\u002F..\u002Fsrc\u002Fhooks\u002FuseTheme';\n\nexport default function NewTripScreen() {\n  const router = useRouter();\n  const { colors } = useTheme();\n  const [title, setTitle] = useState('');\n  const [startDate, setStartDate] = useState('');\n\n  async function handleCreate() {\n    if (!title.trim() || !startDate.trim()) {\n      alert('Заповніть всі поля');\n      return;\n    }\n\n    \u002F\u002F Створити запис у локальній базі\n    const trip = await tripsDb.create({\n      title: title.trim(),\n      startDate: startDate.trim(),\n      syncStatus: 'pending',\n    });\n\n    \u002F\u002F Додати в outbox для синхронізації\n    await outboxDb.add({\n      operation: 'CREATE',\n      resource: 'trip',\n      payload: { id: trip.id, title: trip.title, startDate: trip.startDate },\n    });\n\n    router.back();\n  }\n\n  return (\n    \u003CScreen>\n      \u003CView style={styles.content}>\n        \u003CAppText variant=\"title\">Нова поїздка\u003C\u002FAppText>\n\n        \u003CView style={styles.field}>\n          \u003CAppText variant=\"label\">Назва поїздки\u003C\u002FAppText>\n          \u003CTextInput\n            style={[styles.input, { \n              backgroundColor: colors.surface, \n              color: colors.text \n            }]}\n            placeholder=\"Наприклад: Париж 2026\"\n            placeholderTextColor={colors.textSecondary}\n            value={title}\n            onChangeText={setTitle}\n          \u002F>\n        \u003C\u002FView>\n\n        \u003CView style={styles.field}>\n          \u003CAppText variant=\"label\">Дата початку\u003C\u002FAppText>\n          \u003CTextInput\n            style={[styles.input, { \n              backgroundColor: colors.surface, \n              color: colors.text \n            }]}\n            placeholder=\"YYYY-MM-DD\"\n            placeholderTextColor={colors.textSecondary}\n            value={startDate}\n            onChangeText={setStartDate}\n          \u002F>\n        \u003C\u002FView>\n\n        \u003CView style={styles.buttons}>\n          \u003CButton\n            title=\"Створити\"\n            onPress={handleCreate}\n            variant=\"primary\"\n            style={styles.button}\n          \u002F>\n          \u003CButton\n            title=\"Скасувати\"\n            onPress={() => router.back()}\n            variant=\"secondary\"\n            style={styles.button}\n          \u002F>\n        \u003C\u002FView>\n      \u003C\u002FView>\n    \u003C\u002FScreen>\n  );\n}\n\nconst styles = StyleSheet.create({\n  content: {\n    padding: 16,\n  },\n  field: {\n    marginBottom: 16,\n  },\n  input: {\n    borderRadius: 8,\n    paddingHorizontal: 12,\n    paddingVertical: 10,\n    fontSize: 16,\n    borderWidth: 1,\n    borderColor: '#ddd',\n  },\n  buttons: {\n    marginTop: 24,\n    gap: 12,\n  },\n  button: {\n    width: '100%',\n  },\n});\n","app\u002Ftrip\u002Fnew.tsx",[3780,18033,18034,18058,18074,18090,18106,18122,18140,18156,18172,18188,18192,18205,18217,18231,18254,18277,18281,18292,18315,18327,18334,18338,18342,18347,18365,18378,18392,18400,18404,18408,18413,18425,18433,18441,18477,18481,18485,18497,18501,18505,18511,18519,18533,18560,18564,18579,18606,18612,18622,18627,18632,18637,18651,18659,18670,18681,18685,18693,18697,18711,18737,18743,18751,18755,18759,18763,18768,18773,18778,18783,18787,18792,18796,18801,18806,18811,18816,18821,18826,18830,18834,18839,18844,18849,18853,18857,18861,18866,18870,18874,18878,18882,18886,18892,18900,18904,18911,18919,18923,18929,18937,18945,18953,18961,18969,18977,18981,18988,18996,19004,19008,19015,19024,19028],{"__ignoreMap":3978},[3982,18035,18036,18038,18040,18042,18044,18046,18048,18050,18052,18054,18056],{"class":3984,"line":3985},[3982,18037,5211],{"class":5210},[3982,18039,5444],{"class":3996},[3982,18041,5728],{"class":4003},[3982,18043,3783],{"class":3996},[3982,18045,7543],{"class":4003},[3982,18047,3783],{"class":3996},[3982,18049,7558],{"class":4003},[3982,18051,5455],{"class":3996},[3982,18053,5458],{"class":5210},[3982,18055,7565],{"class":4028},[3982,18057,4043],{"class":3996},[3982,18059,18060,18062,18064,18066,18068,18070,18072],{"class":3984,"line":4000},[3982,18061,5211],{"class":5210},[3982,18063,5444],{"class":3996},[3982,18065,16105],{"class":4003},[3982,18067,5455],{"class":3996},[3982,18069,5458],{"class":5210},[3982,18071,7470],{"class":4028},[3982,18073,4043],{"class":3996},[3982,18075,18076,18078,18080,18082,18084,18086,18088],{"class":3984,"line":4020},[3982,18077,5211],{"class":5210},[3982,18079,5444],{"class":3996},[3982,18081,5452],{"class":4003},[3982,18083,5455],{"class":3996},[3982,18085,5458],{"class":5210},[3982,18087,5461],{"class":4028},[3982,18089,4043],{"class":3996},[3982,18091,18092,18094,18096,18098,18100,18102,18104],{"class":3984,"line":4046},[3982,18093,5211],{"class":5210},[3982,18095,5444],{"class":3996},[3982,18097,16142],{"class":4003},[3982,18099,5455],{"class":3996},[3982,18101,5458],{"class":5210},[3982,18103,16149],{"class":4028},[3982,18105,4043],{"class":3996},[3982,18107,18108,18110,18112,18114,18116,18118,18120],{"class":3984,"line":4069},[3982,18109,5211],{"class":5210},[3982,18111,5444],{"class":3996},[3982,18113,16160],{"class":4003},[3982,18115,5455],{"class":3996},[3982,18117,5458],{"class":5210},[3982,18119,16167],{"class":4028},[3982,18121,4043],{"class":3996},[3982,18123,18124,18126,18128,18131,18133,18135,18138],{"class":3984,"line":4086},[3982,18125,5211],{"class":5210},[3982,18127,5444],{"class":3996},[3982,18129,18130],{"class":4003},"AppText",[3982,18132,5455],{"class":3996},[3982,18134,5458],{"class":5210},[3982,18136,18137],{"class":4028}," '..\u002F..\u002Fsrc\u002Fshared\u002Fui\u002FAppText'",[3982,18139,4043],{"class":3996},[3982,18141,18142,18144,18146,18148,18150,18152,18154],{"class":3984,"line":4103},[3982,18143,5211],{"class":5210},[3982,18145,5444],{"class":3996},[3982,18147,14443],{"class":4003},[3982,18149,5455],{"class":3996},[3982,18151,5458],{"class":5210},[3982,18153,16220],{"class":4028},[3982,18155,4043],{"class":3996},[3982,18157,18158,18160,18162,18164,18166,18168,18170],{"class":3984,"line":4119},[3982,18159,5211],{"class":5210},[3982,18161,5444],{"class":3996},[3982,18163,14438],{"class":4003},[3982,18165,5455],{"class":3996},[3982,18167,5458],{"class":5210},[3982,18169,16801],{"class":4028},[3982,18171,4043],{"class":3996},[3982,18173,18174,18176,18178,18180,18182,18184,18186],{"class":3984,"line":4135},[3982,18175,5211],{"class":5210},[3982,18177,5444],{"class":3996},[3982,18179,16828],{"class":4003},[3982,18181,5455],{"class":3996},[3982,18183,5458],{"class":5210},[3982,18185,16835],{"class":4028},[3982,18187,4043],{"class":3996},[3982,18189,18190],{"class":3984,"line":4859},[3982,18191,4832],{"emptyLinePlaceholder":4831},[3982,18193,18194,18196,18198,18200,18203],{"class":3984,"line":4865},[3982,18195,5484],{"class":5210},[3982,18197,7483],{"class":5210},[3982,18199,5487],{"class":3988},[3982,18201,18202],{"class":5253}," NewTripScreen",[3982,18204,5493],{"class":3996},[3982,18206,18207,18209,18211,18213,18215],{"class":3984,"line":4871},[3982,18208,5498],{"class":3988},[3982,18210,16280],{"class":5239},[3982,18212,5243],{"class":3996},[3982,18214,16105],{"class":5253},[3982,18216,5257],{"class":3996},[3982,18218,18219,18221,18223,18225,18227,18229],{"class":3984,"line":4877},[3982,18220,5498],{"class":3988},[3982,18222,5444],{"class":3996},[3982,18224,16899],{"class":5239},[3982,18226,7702],{"class":3996},[3982,18228,16828],{"class":5253},[3982,18230,5257],{"class":3996},[3982,18232,18233,18235,18237,18239,18241,18244,18246,18248,18250,18252],{"class":3984,"line":4883},[3982,18234,5498],{"class":3988},[3982,18236,5501],{"class":3996},[3982,18238,7924],{"class":5239},[3982,18240,3783],{"class":3996},[3982,18242,18243],{"class":5239},"setTitle",[3982,18245,5512],{"class":3996},[3982,18247,5452],{"class":5253},[3982,18249,5270],{"class":3996},[3982,18251,7678],{"class":4028},[3982,18253,5375],{"class":3996},[3982,18255,18256,18258,18260,18262,18264,18267,18269,18271,18273,18275],{"class":3984,"line":4888},[3982,18257,5498],{"class":3988},[3982,18259,5501],{"class":3996},[3982,18261,17267],{"class":5239},[3982,18263,3783],{"class":3996},[3982,18265,18266],{"class":5239},"setStartDate",[3982,18268,5512],{"class":3996},[3982,18270,5452],{"class":5253},[3982,18272,5270],{"class":3996},[3982,18274,7678],{"class":4028},[3982,18276,5375],{"class":3996},[3982,18278,18279],{"class":3984,"line":4893},[3982,18280,4832],{"emptyLinePlaceholder":4831},[3982,18282,18283,18285,18287,18290],{"class":3984,"line":4899},[3982,18284,10495],{"class":3988},[3982,18286,5487],{"class":3988},[3982,18288,18289],{"class":5253}," handleCreate",[3982,18291,5493],{"class":3996},[3982,18293,18294,18296,18298,18300,18302,18304,18307,18309,18311,18313],{"class":3984,"line":4905},[3982,18295,6324],{"class":5210},[3982,18297,10382],{"class":3996},[3982,18299,7924],{"class":4003},[3982,18301,3823],{"class":3996},[3982,18303,7764],{"class":5253},[3982,18305,18306],{"class":3996},"() || !",[3982,18308,17267],{"class":4003},[3982,18310,3823],{"class":3996},[3982,18312,7764],{"class":5253},[3982,18314,7767],{"class":3996},[3982,18316,18317,18320,18322,18325],{"class":3984,"line":4911},[3982,18318,18319],{"class":5253},"      alert",[3982,18321,5270],{"class":3996},[3982,18323,18324],{"class":4028},"'Заповніть всі поля'",[3982,18326,5375],{"class":3996},[3982,18328,18329,18332],{"class":3984,"line":4916},[3982,18330,18331],{"class":5210},"      return",[3982,18333,4043],{"class":3996},[3982,18335,18336],{"class":3984,"line":4921},[3982,18337,6492],{"class":3996},[3982,18339,18340],{"class":3984,"line":4927},[3982,18341,4832],{"emptyLinePlaceholder":4831},[3982,18343,18344],{"class":3984,"line":4933},[3982,18345,18346],{"class":4016},"    \u002F\u002F Створити запис у локальній базі\n",[3982,18348,18349,18351,18353,18355,18357,18359,18361,18363],{"class":3984,"line":4938},[3982,18350,5598],{"class":3988},[3982,18352,13301],{"class":5239},[3982,18354,5243],{"class":3996},[3982,18356,5246],{"class":5210},[3982,18358,12345],{"class":4003},[3982,18360,3823],{"class":3996},[3982,18362,9112],{"class":5253},[3982,18364,15926],{"class":3996},[3982,18366,18367,18369,18372,18374,18376],{"class":3984,"line":4943},[3982,18368,12459],{"class":4003},[3982,18370,18371],{"class":4003}," title",[3982,18373,3823],{"class":3996},[3982,18375,7764],{"class":5253},[3982,18377,6482],{"class":3996},[3982,18379,18380,18383,18386,18388,18390],{"class":3984,"line":4949},[3982,18381,18382],{"class":4003},"      startDate:",[3982,18384,18385],{"class":4003}," startDate",[3982,18387,3823],{"class":3996},[3982,18389,7764],{"class":5253},[3982,18391,6482],{"class":3996},[3982,18393,18394,18396,18398],{"class":3984,"line":4954},[3982,18395,9637],{"class":4003},[3982,18397,9640],{"class":4028},[3982,18399,6287],{"class":3996},[3982,18401,18402],{"class":3984,"line":4960},[3982,18403,5640],{"class":3996},[3982,18405,18406],{"class":3984,"line":4966},[3982,18407,4832],{"emptyLinePlaceholder":4831},[3982,18409,18410],{"class":3984,"line":4972},[3982,18411,18412],{"class":4016},"    \u002F\u002F Додати в outbox для синхронізації\n",[3982,18414,18415,18417,18419,18421,18423],{"class":3984,"line":4978},[3982,18416,6515],{"class":5210},[3982,18418,13616],{"class":4003},[3982,18420,3823],{"class":3996},[3982,18422,17209],{"class":5253},[3982,18424,15926],{"class":3996},[3982,18426,18427,18429,18431],{"class":3984,"line":4983},[3982,18428,13779],{"class":4003},[3982,18430,13790],{"class":4028},[3982,18432,6287],{"class":3996},[3982,18434,18435,18437,18439],{"class":3984,"line":4989},[3982,18436,13805],{"class":4003},[3982,18438,13816],{"class":4028},[3982,18440,6287],{"class":3996},[3982,18442,18443,18445,18447,18449,18451,18453,18455,18457,18459,18461,18463,18465,18467,18469,18471,18473,18475],{"class":3984,"line":4995},[3982,18444,13827],{"class":4003},[3982,18446,5444],{"class":3996},[3982,18448,9841],{"class":4003},[3982,18450,13301],{"class":4003},[3982,18452,3823],{"class":3996},[3982,18454,5166],{"class":4003},[3982,18456,3783],{"class":3996},[3982,18458,17249],{"class":4003},[3982,18460,13301],{"class":4003},[3982,18462,3823],{"class":3996},[3982,18464,7924],{"class":4003},[3982,18466,3783],{"class":3996},[3982,18468,17260],{"class":4003},[3982,18470,13301],{"class":4003},[3982,18472,3823],{"class":3996},[3982,18474,17267],{"class":4003},[3982,18476,6978],{"class":3996},[3982,18478,18479],{"class":3984,"line":5001},[3982,18480,5640],{"class":3996},[3982,18482,18483],{"class":3984,"line":5007},[3982,18484,4832],{"emptyLinePlaceholder":4831},[3982,18486,18487,18490,18492,18495],{"class":3984,"line":5013},[3982,18488,18489],{"class":4003},"    router",[3982,18491,3823],{"class":3996},[3982,18493,18494],{"class":5253},"back",[3982,18496,5257],{"class":3996},[3982,18498,18499],{"class":3984,"line":5018},[3982,18500,5417],{"class":3996},[3982,18502,18503],{"class":3984,"line":5024},[3982,18504,4832],{"emptyLinePlaceholder":4831},[3982,18506,18507,18509],{"class":3984,"line":5030},[3982,18508,5667],{"class":5210},[3982,18510,5720],{"class":3996},[3982,18512,18513,18515,18517],{"class":3984,"line":5035},[3982,18514,5725],{"class":3996},[3982,18516,16142],{"class":3992},[3982,18518,5731],{"class":3996},[3982,18520,18521,18523,18525,18527,18529,18531],{"class":3984,"line":8065},[3982,18522,7915],{"class":3996},[3982,18524,5728],{"class":4003},[3982,18526,7822],{"class":4003},[3982,18528,7825],{"class":3996},[3982,18530,17407],{"class":4003},[3982,18532,7831],{"class":3996},[3982,18534,18535,18537,18539,18541,18543,18545,18548,18551,18554,18556,18558],{"class":3984,"line":8086},[3982,18536,5746],{"class":3996},[3982,18538,18130],{"class":4003},[3982,18540,5752],{"class":4003},[3982,18542,5755],{"class":3996},[3982,18544,6818],{"class":4028},[3982,18546,18547],{"class":3996},">",[3982,18549,18550],{"class":4003},"Нова",[3982,18552,18553],{"class":4003}," поїздка",[3982,18555,7890],{"class":3996},[3982,18557,18130],{"class":4003},[3982,18559,5731],{"class":3996},[3982,18561,18562],{"class":3984,"line":8095},[3982,18563,4832],{"emptyLinePlaceholder":4831},[3982,18565,18566,18568,18570,18572,18574,18577],{"class":3984,"line":8105},[3982,18567,5746],{"class":3996},[3982,18569,5728],{"class":4003},[3982,18571,7822],{"class":4003},[3982,18573,7825],{"class":3996},[3982,18575,18576],{"class":4003},"field",[3982,18578,7831],{"class":3996},[3982,18580,18581,18583,18585,18587,18589,18592,18594,18597,18600,18602,18604],{"class":3984,"line":8110},[3982,18582,7868],{"class":3996},[3982,18584,18130],{"class":4003},[3982,18586,5752],{"class":4003},[3982,18588,5755],{"class":3996},[3982,18590,18591],{"class":4028},"\"label\"",[3982,18593,18547],{"class":3996},[3982,18595,18596],{"class":4003},"Назва",[3982,18598,18599],{"class":4003}," поїздки",[3982,18601,7890],{"class":3996},[3982,18603,18130],{"class":4003},[3982,18605,5731],{"class":3996},[3982,18607,18608,18610],{"class":3984,"line":8120},[3982,18609,7868],{"class":3996},[3982,18611,7975],{"class":4003},[3982,18613,18614,18617,18619],{"class":3984,"line":8128},[3982,18615,18616],{"class":4003},"            style",[3982,18618,8005],{"class":3996},[3982,18620,18621],{"class":4003},"[styles.input, { \n",[3982,18623,18624],{"class":3984,"line":8140},[3982,18625,18626],{"class":4003},"              backgroundColor: colors.surface, \n",[3982,18628,18629],{"class":3984,"line":8153},[3982,18630,18631],{"class":4003},"              color: colors.text \n",[3982,18633,18634],{"class":3984,"line":8167},[3982,18635,18636],{"class":4003},"            }]}\n",[3982,18638,18639,18642,18645,18648],{"class":3984,"line":8183},[3982,18640,18641],{"class":4003},"            placeholder=\"Наприклад:",[3982,18643,18644],{"class":4003}," Париж",[3982,18646,18647],{"class":6014}," 2026",[3982,18649,18650],{"class":4028},"\"\n",[3982,18652,18653,18656],{"class":3984,"line":8208},[3982,18654,18655],{"class":4028},"            placeholderTextColor={colors.textSecondary",[3982,18657,4852],{"class":18658},"se1LK",[3982,18660,18661,18664,18666,18668],{"class":3984,"line":8223},[3982,18662,18663],{"class":4003},"            value",[3982,18665,8005],{"class":3996},[3982,18667,7924],{"class":4003},[3982,18669,4852],{"class":3996},[3982,18671,18672,18675,18677,18679],{"class":3984,"line":8241},[3982,18673,18674],{"class":4003},"            onChangeText",[3982,18676,8005],{"class":3996},[3982,18678,18243],{"class":4003},[3982,18680,4852],{"class":3996},[3982,18682,18683],{"class":3984,"line":8271},[3982,18684,16585],{"class":3996},[3982,18686,18687,18689,18691],{"class":3984,"line":8277},[3982,18688,5800],{"class":3996},[3982,18690,5728],{"class":4003},[3982,18692,5731],{"class":3996},[3982,18694,18695],{"class":3984,"line":8294},[3982,18696,4832],{"emptyLinePlaceholder":4831},[3982,18698,18699,18701,18703,18705,18707,18709],{"class":3984,"line":8308},[3982,18700,5746],{"class":3996},[3982,18702,5728],{"class":4003},[3982,18704,7822],{"class":4003},[3982,18706,7825],{"class":3996},[3982,18708,18576],{"class":4003},[3982,18710,7831],{"class":3996},[3982,18712,18713,18715,18717,18719,18721,18723,18725,18728,18731,18733,18735],{"class":3984,"line":8313},[3982,18714,7868],{"class":3996},[3982,18716,18130],{"class":4003},[3982,18718,5752],{"class":4003},[3982,18720,5755],{"class":3996},[3982,18722,18591],{"class":4028},[3982,18724,18547],{"class":3996},[3982,18726,18727],{"class":4003},"Дата",[3982,18729,18730],{"class":4003}," початку",[3982,18732,7890],{"class":3996},[3982,18734,18130],{"class":4003},[3982,18736,5731],{"class":3996},[3982,18738,18739,18741],{"class":3984,"line":8319},[3982,18740,7868],{"class":3996},[3982,18742,7975],{"class":4003},[3982,18744,18745,18747,18749],{"class":3984,"line":8325},[3982,18746,18616],{"class":4003},[3982,18748,8005],{"class":3996},[3982,18750,18621],{"class":4003},[3982,18752,18753],{"class":3984,"line":8330},[3982,18754,18626],{"class":4003},[3982,18756,18757],{"class":3984,"line":8336},[3982,18758,18631],{"class":4003},[3982,18760,18761],{"class":3984,"line":8342},[3982,18762,18636],{"class":4003},[3982,18764,18765],{"class":3984,"line":8348},[3982,18766,18767],{"class":4003},"            placeholder=\"YYYY-MM-DD\"\n",[3982,18769,18770],{"class":3984,"line":8354},[3982,18771,18772],{"class":4003},"            placeholderTextColor={colors.textSecondary}\n",[3982,18774,18775],{"class":3984,"line":8360},[3982,18776,18777],{"class":4003},"            value={startDate}\n",[3982,18779,18780],{"class":3984,"line":8366},[3982,18781,18782],{"class":4003},"            onChangeText={setStartDate}\n",[3982,18784,18785],{"class":3984,"line":8372},[3982,18786,16585],{"class":4003},[3982,18788,18789],{"class":3984,"line":8377},[3982,18790,18791],{"class":4003},"        \u003C\u002FView>\n",[3982,18793,18794],{"class":3984,"line":8383},[3982,18795,4832],{"emptyLinePlaceholder":4831},[3982,18797,18798],{"class":3984,"line":8389},[3982,18799,18800],{"class":4003},"        \u003CView style={styles.buttons}>\n",[3982,18802,18803],{"class":3984,"line":8395},[3982,18804,18805],{"class":4003},"          \u003CButton\n",[3982,18807,18808],{"class":3984,"line":8401},[3982,18809,18810],{"class":4003},"            title=\"Створити\"\n",[3982,18812,18813],{"class":3984,"line":8407},[3982,18814,18815],{"class":4003},"            onPress={handleCreate}\n",[3982,18817,18818],{"class":3984,"line":8413},[3982,18819,18820],{"class":4003},"            variant=\"primary\"\n",[3982,18822,18823],{"class":3984,"line":8418},[3982,18824,18825],{"class":4003},"            style={styles.button}\n",[3982,18827,18828],{"class":3984,"line":8423},[3982,18829,16585],{"class":4003},[3982,18831,18832],{"class":3984,"line":8428},[3982,18833,18805],{"class":4003},[3982,18835,18836],{"class":3984,"line":8434},[3982,18837,18838],{"class":4003},"            title=\"Скасувати\"\n",[3982,18840,18841],{"class":3984,"line":8458},[3982,18842,18843],{"class":4003},"            onPress={() => router.back()}\n",[3982,18845,18846],{"class":3984,"line":8466},[3982,18847,18848],{"class":4003},"            variant=\"secondary\"\n",[3982,18850,18851],{"class":3984,"line":8477},[3982,18852,18825],{"class":4003},[3982,18854,18855],{"class":3984,"line":8488},[3982,18856,16585],{"class":4003},[3982,18858,18859],{"class":3984,"line":8499},[3982,18860,18791],{"class":4003},[3982,18862,18863],{"class":3984,"line":8505},[3982,18864,18865],{"class":4003},"      \u003C\u002FView>\n",[3982,18867,18868],{"class":3984,"line":8529},[3982,18869,16603],{"class":4003},[3982,18871,18872],{"class":3984,"line":8537},[3982,18873,5833],{"class":4003},[3982,18875,18876],{"class":3984,"line":8548},[3982,18877,4852],{"class":4003},[3982,18879,18880],{"class":3984,"line":8559},[3982,18881,4832],{"emptyLinePlaceholder":4831},[3982,18883,18884],{"class":3984,"line":8569},[3982,18885,8431],{"class":4003},[3982,18887,18888,18890],{"class":3984,"line":8574},[3982,18889,17745],{"class":4003},[3982,18891,5342],{"class":3996},[3982,18893,18894,18896,18898],{"class":3984,"line":8582},[3982,18895,8480],{"class":4003},[3982,18897,8564],{"class":6014},[3982,18899,6287],{"class":3996},[3982,18901,18902],{"class":3984,"line":8593},[3982,18903,8502],{"class":3996},[3982,18905,18906,18909],{"class":3984,"line":8602},[3982,18907,18908],{"class":4003},"  field:",[3982,18910,5342],{"class":3996},[3982,18912,18913,18915,18917],{"class":3984,"line":8613},[3982,18914,16650],{"class":4003},[3982,18916,8564],{"class":6014},[3982,18918,6287],{"class":3996},[3982,18920,18921],{"class":3984,"line":8618},[3982,18922,8502],{"class":3996},[3982,18924,18925,18927],{"class":3984,"line":8626},[3982,18926,8621],{"class":4003},[3982,18928,5342],{"class":3996},[3982,18930,18931,18933,18935],{"class":3984,"line":8636},[3982,18932,8648],{"class":4003},[3982,18934,8608],{"class":6014},[3982,18936,6287],{"class":3996},[3982,18938,18939,18941,18943],{"class":3984,"line":8645},[3982,18940,8658],{"class":4003},[3982,18942,8483],{"class":6014},[3982,18944,6287],{"class":3996},[3982,18946,18947,18949,18951],{"class":3984,"line":8655},[3982,18948,8668],{"class":4003},[3982,18950,8671],{"class":6014},[3982,18952,6287],{"class":3996},[3982,18954,18955,18957,18959],{"class":3984,"line":8665},[3982,18956,8540],{"class":4003},[3982,18958,8564],{"class":6014},[3982,18960,6287],{"class":3996},[3982,18962,18963,18965,18967],{"class":3984,"line":8676},[3982,18964,8679],{"class":4003},[3982,18966,8445],{"class":6014},[3982,18968,6287],{"class":3996},[3982,18970,18971,18973,18975],{"class":3984,"line":8686},[3982,18972,8689],{"class":4003},[3982,18974,8692],{"class":4028},[3982,18976,6287],{"class":3996},[3982,18978,18979],{"class":3984,"line":8697},[3982,18980,8502],{"class":3996},[3982,18982,18983,18986],{"class":3984,"line":8702},[3982,18984,18985],{"class":4003},"  buttons:",[3982,18987,5342],{"class":3996},[3982,18989,18990,18992,18994],{"class":3984,"line":8710},[3982,18991,18013],{"class":4003},[3982,18993,8543],{"class":6014},[3982,18995,6287],{"class":3996},[3982,18997,18998,19000,19002],{"class":3984,"line":8720},[3982,18999,8605],{"class":4003},[3982,19001,8483],{"class":6014},[3982,19003,6287],{"class":3996},[3982,19005,19006],{"class":3984,"line":8731},[3982,19007,8502],{"class":3996},[3982,19009,19010,19013],{"class":3984,"line":8741},[3982,19011,19012],{"class":4003},"  button:",[3982,19014,5342],{"class":3996},[3982,19016,19017,19019,19022],{"class":3984,"line":8750},[3982,19018,8723],{"class":4003},[3982,19020,19021],{"class":4028}," '100%'",[3982,19023,6287],{"class":3996},[3982,19025,19026],{"class":3984,"line":8759},[3982,19027,8502],{"class":3996},[3982,19029,19030],{"class":3984,"line":8769},[3982,19031,5422],{"class":3996},[3743,19033,19034],{},"::",[3836,19036],{},[3825,19038,19039,19065],{},[3743,19040,19041,19044,19047,19048,3783,19051,3783,19054,19057,19058,19064],{},[3747,19042,19043],{},"Повні лістинги файлів Nomad:",[19045,19046],"br",{},"\nЧерез великий обсяг коду екранів (",[3780,19049,19050],{},"app\u002F(tabs)\u002Ftrips\u002Findex.tsx",[3780,19052,19053],{},"app\u002F(tabs)\u002Ftrips\u002F[id].tsx",[3780,19055,19056],{},"app\u002Fcreate-trip.tsx",") повні лістинги доступні в ",[11138,19059,19063],{"href":19060,"rel":19061},"https:\u002F\u002Fgithub.com\u002Farakviel\u002Fnomad",[19062],"nofollow","репозиторії Nomad"," після коміту цієї статті. Основні зміни:",[3762,19066,19067,19084,19097,19109,19121],{},[3765,19068,19069,19073,19074,19077,19078,19080,19081,19083],{},[3747,19070,19071],{},[3780,19072,19050],{},": додано ",[3780,19075,19076],{},"useSyncWorker()",", завантаження з ",[3780,19079,14443],{},", відображення ",[3780,19082,16196],{},", об'єднання локальних і API-поїздок.",[3765,19085,19086,19090,19091,19094,19095,3823],{},[3747,19087,19088],{},[3780,19089,19056],{},": зберігання в ",[3780,19092,19093],{},"tripsDb.create()"," + додавання в ",[3780,19096,14438],{},[3765,19098,19099,19103,19104,19106,19107,3823],{},[3747,19100,19101],{},[3780,19102,19053],{},": завантаження локальної версії з ",[3780,19105,14443],{},", відображення sync status, кнопка «Повторити» для ",[3780,19108,3789],{},[3765,19110,19111,19116,19117,19120],{},[3747,19112,19113],{},[3780,19114,19115],{},"src\u002Ffeatures\u002Ftrips\u002Fui\u002FTripCard.tsx",": приймає ",[3780,19118,19119],{},"trip & { syncStatus, syncError }",", показує sync badge.",[3765,19122,19123,19127,19128,19131],{},[3747,19124,19125],{},[3780,19126,7452],{},": виклик ",[3780,19129,19130],{},"initDatabase()"," при запуску.",[3836,19133],{},[3843,19135,19137],{"id":19136},"перевірка","Перевірка",[3743,19139,19140],{},"Після інтеграції коду перевірте:",[3927,19142,19143,19159,19180,19208,19229],{},[3765,19144,19145,19148],{},[3747,19146,19147],{},"Створення поїздки онлайн:",[3762,19149,19150,19153,19156],{},[3765,19151,19152],{},"Запустити застосунок з увімкненою мережею.",[3765,19154,19155],{},"Натиснути «+ Нова поїздка», заповнити форму, зберегти.",[3765,19157,19158],{},"У списку поїздок біля картки через ~10 секунд badge змінюється з «⏳ Не синхронізовано» на «✅ Синхронізовано» (зникає).",[3765,19160,19161,19164],{},[3747,19162,19163],{},"Створення поїздки офлайн:",[3762,19165,19166,19169,19172,19175],{},[3765,19167,19168],{},"Вимкнути Wi-Fi на пристрої (Settings → Wi-Fi → Off).",[3765,19170,19171],{},"Побачити жовтий banner «📡 Офлайн-режим» у header списку.",[3765,19173,19174],{},"Створити нову поїздку → вона одразу з'являється в списку з badge «⏳ Не синхронізовано».",[3765,19176,19177,19178,4471],{},"Увімкнути Wi-Fi → через 10–20 секунд badge зникає (статус ",[3780,19179,3786],{},[3765,19181,19182,19185],{},[3747,19183,19184],{},"Помилка синхронізації:",[3762,19186,19187,19196,19199,19202],{},[3765,19188,7109,19189,19192,19193,4471],{},[3780,19190,19191],{},"useSyncWorker.ts"," змінити URL API на неіснуючий (",[3780,19194,19195],{},"https:\u002F\u002Fnonexistent.api.com\u002Ftrips",[3765,19197,19198],{},"Створити поїздку → через кілька секунд badge «❌ Помилка».",[3765,19200,19201],{},"Відкрити деталі поїздки → бачити текст помилки + кнопку «Повторити синхронізацію».",[3765,19203,19204,19205,19207],{},"Натиснути «Повторити» → статус знову ",[3780,19206,3782],{},", worker спробує ще раз.",[3765,19209,19210,19213],{},[3747,19211,19212],{},"Persistence після перезапуску:",[3762,19214,19215,19218,19221,19226],{},[3765,19216,19217],{},"Створити 2–3 поїздки офлайн (мережа вимкнена).",[3765,19219,19220],{},"Закрити застосунок (force-quit).",[3765,19222,19223,19224,3823],{},"Відкрити знову → поїздки лишаються в списку з ",[3780,19225,4151],{},[3765,19227,19228],{},"Увімкнути мережу → через 10 секунд всі синхронізуються.",[3765,19230,19231,19234],{},[3747,19232,19233],{},"Exponential backoff:",[3762,19235,19236,19239],{},[3765,19237,19238],{},"Залишити API неробочим, створити поїздку.",[3765,19240,19241,19242,11520,19245,19247],{},"Спостерігати консоль (або ",[3780,19243,19244],{},"console.log",[3780,19246,5091],{},") — інтервали між retry зростають: 2 с, 4 с, 8 с, 16 с, …",[3836,19249],{},[3843,19251,19253],{"id":19252},"коміт","Коміт",[3973,19255,19257],{"className":10946,"code":19256,"language":10948,"meta":3978,"style":3978},"cd \u002Fpath\u002Fto\u002Fnomad\ngit add -A\ngit commit -m \"$(cat \u003C\u003C'EOF'\nfeat: offline queue and sync status\n\n- Added syncStatus (pending\u002Fsyncing\u002Fsynced\u002Ferror) to Trip and Place types\n- Created outbox table in SQLite for queued operations\n- Implemented useSyncWorker hook with exponential backoff\n- Added OfflineBanner component (network status indicator)\n- Added sync badge to TripCard (shows sync status)\n- Added retry button in trip details for failed syncs\n- Integrated NetInfo for network state detection\n- Auto-sync every 10 seconds when online\n\nMaterial: content\u002F15.react-native\u002Fversion2\u002F20.offline-first-sync.md\nEOF\n)\"\ngit push\n",[3780,19258,19259,19266,19276,19298,19303,19307,19312,19317,19322,19327,19332,19337,19342,19347,19351,19356,19361,19366],{"__ignoreMap":3978},[3982,19260,19261,19263],{"class":3984,"line":3985},[3982,19262,10972],{"class":5253},[3982,19264,19265],{"class":4028}," \u002Fpath\u002Fto\u002Fnomad\n",[3982,19267,19268,19271,19273],{"class":3984,"line":4000},[3982,19269,19270],{"class":5253},"git",[3982,19272,13878],{"class":4028},[3982,19274,19275],{"class":3988}," -A\n",[3982,19277,19278,19280,19283,19286,19289,19292,19295],{"class":3984,"line":4020},[3982,19279,19270],{"class":5253},[3982,19281,19282],{"class":4028}," commit",[3982,19284,19285],{"class":3988}," -m",[3982,19287,19288],{"class":4028}," \"$(",[3982,19290,19291],{"class":5253},"cat",[3982,19293,19294],{"class":3996}," \u003C\u003C",[3982,19296,19297],{"class":4028},"'EOF'\n",[3982,19299,19300],{"class":3984,"line":4046},[3982,19301,19302],{"class":4028},"feat: offline queue and sync status\n",[3982,19304,19305],{"class":3984,"line":4069},[3982,19306,4832],{"emptyLinePlaceholder":4831},[3982,19308,19309],{"class":3984,"line":4086},[3982,19310,19311],{"class":4028},"- Added syncStatus (pending\u002Fsyncing\u002Fsynced\u002Ferror) to Trip and Place types\n",[3982,19313,19314],{"class":3984,"line":4103},[3982,19315,19316],{"class":4028},"- Created outbox table in SQLite for queued operations\n",[3982,19318,19319],{"class":3984,"line":4119},[3982,19320,19321],{"class":4028},"- Implemented useSyncWorker hook with exponential backoff\n",[3982,19323,19324],{"class":3984,"line":4135},[3982,19325,19326],{"class":4028},"- Added OfflineBanner component (network status indicator)\n",[3982,19328,19329],{"class":3984,"line":4859},[3982,19330,19331],{"class":4028},"- Added sync badge to TripCard (shows sync status)\n",[3982,19333,19334],{"class":3984,"line":4865},[3982,19335,19336],{"class":4028},"- Added retry button in trip details for failed syncs\n",[3982,19338,19339],{"class":3984,"line":4871},[3982,19340,19341],{"class":4028},"- Integrated NetInfo for network state detection\n",[3982,19343,19344],{"class":3984,"line":4877},[3982,19345,19346],{"class":4028},"- Auto-sync every 10 seconds when online\n",[3982,19348,19349],{"class":3984,"line":4883},[3982,19350,4832],{"emptyLinePlaceholder":4831},[3982,19352,19353],{"class":3984,"line":4888},[3982,19354,19355],{"class":4028},"Material: content\u002F15.react-native\u002Fversion2\u002F20.offline-first-sync.md\n",[3982,19357,19358],{"class":3984,"line":4893},[3982,19359,19360],{"class":4028},"EOF\n",[3982,19362,19363],{"class":3984,"line":4899},[3982,19364,19365],{"class":4028},")\"\n",[3982,19367,19368,19370],{"class":3984,"line":4905},[3982,19369,19270],{"class":5253},[3982,19371,19372],{"class":4028}," push\n",[3743,19374,19375,19376,19379,19380,19384],{},"Після ",[3780,19377,19378],{},"git push"," у публічному репо ",[11138,19381,19383],{"href":19060,"rel":19382},[19062],"github.com\u002Farakviel\u002Fnomad"," з'явиться коміт із цим кроком.",[3836,19386],{},[3738,19388,19390],{"id":19389},"частина-4-практичні-завдання","Частина 4. Практичні завдання",[3843,19392,19394],{"id":19393},"basic","Basic",[3927,19396,19397,19416,19449],{},[3765,19398,19399,19402],{},[3747,19400,19401],{},"Пояснити своїми словами:",[3762,19403,19404,19407,19413],{},[3765,19405,19406],{},"Що таке outbox pattern і навіщо він потрібен?",[3765,19408,19409,19410,19412],{},"Які чотири значення може мати ",[3780,19411,3818],{}," і що кожне означає?",[3765,19414,19415],{},"Що таке exponential backoff і навіщо він використовується?",[3765,19417,19418,19421],{},[3747,19419,19420],{},"Код-розбір (міні-проєкт):",[3762,19422,19423,19437],{},[3765,19424,19425,19426,19428,19429,19431,19432,19434,19435,3823],{},"У файлі ",[3780,19427,19191],{}," знайдіть рядок, де оновлюється ",[3780,19430,3818],{}," на ",[3780,19433,4275],{},". Поясніть, чому це робиться саме перед ",[3780,19436,5254],{},[3765,19438,19439,19440,11520,19442,19444,19445,19448],{},"Що станеться, якщо видалити ",[3780,19441,10407],{},[3780,19443,5091],{}," і залишити лише одноразовий виклик ",[3780,19446,19447],{},"syncPendingTasks()"," при монтуванні?",[3765,19450,19451,19454],{},[3747,19452,19453],{},"Міні-модифікація:",[3762,19455,19456,19459],{},[3765,19457,19458],{},"Змінити колір offline-banner з помаранчевого на червоний.",[3765,19460,19461],{},"Додати лічильник pending-операцій у banner: «Офлайн. Очікує синхронізації: 3».",[3836,19463],{},[3843,19465,19467],{"id":19466},"intermediate","Intermediate",[3927,19469,19470,19493,19514],{},[3765,19471,19472,19475],{},[3747,19473,19474],{},"Розширення міні-проєкту:",[3762,19476,19477,19483,19490],{},[3765,19478,19479,19480,3823],{},"Додати кнопку «Видалити» для завдання → видалення має потрапити в outbox як ",[3780,19481,19482],{},"operation: 'DELETE'",[3765,19484,19485,19486,19489],{},"Реалізувати ",[3780,19487,19488],{},"UPDATE"," операцію: можливість редагувати текст завдання офлайн.",[3765,19491,19492],{},"Додати прогрес-бар: якщо в outbox 5 записів, показувати «Синхронізація 2\u002F5».",[3765,19494,19495,19498],{},[3747,19496,19497],{},"Nomad-фіча:",[3762,19499,19500,19508,19511],{},[3765,19501,19502,19503,19505,19506,3823],{},"Додати ",[3780,19504,11467],{}," (місце в поїздці) з тим самим ",[3780,19507,3818],{},[3765,19509,19510],{},"У деталях поїздки показати список місць із sync-badge на кожному.",[3765,19512,19513],{},"Створення місця офлайн → додати в outbox → синхронізувати з API.",[3765,19515,19516,19519],{},[3747,19517,19518],{},"Conflict resolution:",[3762,19520,19521,19532],{},[3765,19522,7109,19523,19525,19526,19528,19529,19531],{},[3780,19524,5091],{}," додати логіку: якщо сервер повертає ",[3780,19527,4356],{},", завантажити серверну версію, порівняти ",[3780,19530,4522],{}," (локальний vs серверний), взяти новішу (Last Write Wins).",[3765,19533,19534],{},"Показати toast «Серверна версія новіша, ваші зміни скинуто» або «Локальна версія новіша, force-update».",[3836,19536],{},[3843,19538,19540],{"id":19539},"pro","Pro",[3927,19542,19543,19565,19587,19614,19627],{},[3765,19544,19545,19548],{},[3747,19546,19547],{},"Batch sync:",[3762,19549,19550,19559],{},[3765,19551,19552,19553,19555,19556,3823],{},"Змінити ",[3780,19554,5091],{}," так, щоб він не відправляв операції по одній, а збирав усі pending за останні 10 секунд і відправляв одним batch-запитом на ",[3780,19557,19558],{},"\u002Fapi\u002Fsync\u002Fbatch",[3765,19560,19561,19562,19564],{},"Обробити відповідь від batch API (масив результатів) і оновити ",[3780,19563,3818],{}," для кожного запису.",[3765,19566,19567,19570],{},[3747,19568,19569],{},"Background sync (native):",[3762,19571,19572,19582],{},[3765,19573,19574,19575,4483,19578,19581],{},"Інтегрувати ",[3780,19576,19577],{},"expo-background-fetch",[3780,19579,19580],{},"expo-task-manager",", щоб синхронізація працювала навіть коли застосунок у фоні або закритий.",[3765,19583,19584,19585,3823],{},"Перевірити: створити поїздку офлайн, згорнути застосунок, увімкнути мережу, почекати 15 хвилин → відкрити застосунок, побачити ",[3780,19586,4178],{},[3765,19588,19589,19592],{},[3747,19590,19591],{},"Outbox retry limit:",[3762,19593,19594,19602,19608],{},[3765,19595,19596,19597,11520,19600,3823],{},"Додати поле ",[3780,19598,19599],{},"maxRetries: 5",[3780,19601,6079],{},[3765,19603,5111,19604,19607],{},[3780,19605,19606],{},"retryCount >= maxRetries"," → перестати пробувати, показати в UI «Синхронізація невдала після 5 спроб. Видалити запис?».",[3765,19609,19610,19611,19613],{},"Користувач може видалити запис з outbox або скинути ",[3780,19612,4189],{}," вручну.",[3765,19615,19616,19619],{},[3747,19617,19618],{},"Manual merge UI:",[3762,19620,19621,19624],{},[3765,19622,19623],{},"При конфлікті (409) не затирати локальну версію автоматично, а показати модальне вікно з двома колонками: «Локальна версія» | «Серверна версія».",[3765,19625,19626],{},"Користувач вибирає, яку залишити, або редагує вручну → відправляє force-update.",[3765,19628,19629,19632],{},[3747,19630,19631],{},"E2E тест (Maestro):",[3762,19633,19634],{},[3765,19635,19636,19637],{},"Написати Maestro flow:\n",[3927,19638,19639,19644,19647,19650,19653,19656],{},[3765,19640,19641,19642,4471],{},"Запустити застосунок, вимкнути мережу (через mock або ",[3780,19643,5854],{},[3765,19645,19646],{},"Створити поїздку «Test Trip».",[3765,19648,19649],{},"Перевірити наявність badge «⏳ Не синхронізовано».",[3765,19651,19652],{},"Увімкнути мережу.",[3765,19654,19655],{},"Почекати 15 секунд.",[3765,19657,19658],{},"Перевірити відсутність badge (або зелену галочку).",[3836,19660],{},[3738,19662,19664],{"id":19663},"висновок","Висновок",[3743,19666,19667],{},"У цій статті ви дізналися:",[3762,19669,19670,19676,19682,19687,19693,19698,19703],{},[3765,19671,19672,19675],{},[3747,19673,19674],{},"Що таке offline-first"," і чому цей підхід природний для мобільних застосунків.",[3765,19677,19678,19681],{},[3747,19679,19680],{},"Outbox pattern"," — як зберігати операції в локальній черзі та відправляти їх у фоні.",[3765,19683,19684,19686],{},[3747,19685,3818],{}," — чотири стани синхронізації (pending, syncing, synced, error) і як їх показувати в UI.",[3765,19688,19689,19692],{},[3747,19690,19691],{},"Конфлікти"," — стратегії розв'язання (Last Write Wins, Server Wins, Manual Merge).",[3765,19694,19695,19697],{},[3747,19696,6609],{}," — розумні повторні спроби без перевантаження сервера.",[3765,19699,19700,19702],{},[3747,19701,5327],{}," — визначення стану мережі в React Native.",[3765,19704,19705,19708],{},[3747,19706,19707],{},"Offline UX"," — banner, badge, retry-кнопки, оптимістичні оновлення.",[3743,19710,19711,19712,19714,19715,19717],{},"Ми реалізували ",[3747,19713,3810],{}," — повноцінний TODO з синхронізацією, який працює онлайн і офлайн. Потім інтегрували ті самі ідеї в ",[3747,19716,3814],{},": поїздки тепер можна створювати без мережі, і застасунок автоматично синхронізує їх при появі інтернету.",[3743,19719,19720,19721,19724,19725,19728,19729,3783,19732,3819,19735,19738],{},"Offline-first — це ",[3747,19722,19723],{},"не просто техніка",", а ",[3747,19726,19727],{},"філософія дизайну",": користувач ніколи не чекає на мережу, він завжди може працювати, а застосунок синхронізує дані сховано. Це робить мобільні застосунки ",[3747,19730,19731],{},"швидкими",[3747,19733,19734],{},"надійними",[3747,19736,19737],{},"приємними у використанні"," — навіть в літаку, метро чи горах.",[3743,19740,19741,19742,19745],{},"У наступній статті ми розглянемо ",[3747,19743,19744],{},"камеру та медіа"," — як робити фото, обирати з галереї, стискати зображення і зберігати їх локально перед синхронізацією з сервером. Поїздки в Nomad отримають обкладинки, а місця — фотографії, які синхронізуються за тим самим outbox-pattern.",[3954,19747,19748,19751,19752,19754,19755,19758],{},[3747,19749,19750],{},"Ключова ідея статті:"," Offline-first означає, що застосунок ",[3747,19753,3833],{}," працює з локальною базою, а синхронізація з сервером — це ",[3747,19756,19757],{},"фонова оптимізація",", а не обов'язкова умова для роботи. Користувач не блокується, не чекає — він просто працює, а дані «самі» з'являються на сервері, коли є можливість.",[3836,19760],{},[3738,19762,19764],{"id":19763},"додаткові-ресурси","Додаткові ресурси",[3762,19766,19767,19775,19783,19791,19799],{},[3765,19768,19769,19774],{},[11138,19770,19773],{"href":19771,"rel":19772},"https:\u002F\u002Fmicroservices.io\u002Fpatterns\u002Fdata\u002Ftransactional-outbox.html",[19062],"Outbox Pattern (Microservices)"," — оригінальний опис патерну для мікросервісів; ідея та сама, але на сервері.",[3765,19776,19777,19782],{},[11138,19778,19781],{"href":19779,"rel":19780},"https:\u002F\u002Fdocs.expo.dev\u002Fversions\u002Flatest\u002Fsdk\u002Fnetinfo\u002F",[19062],"Expo NetInfo Docs"," — офіційна документація.",[3765,19784,19785,19790],{},[11138,19786,19789],{"href":19787,"rel":19788},"https:\u002F\u002Fpouchdb.com\u002Fguides\u002F",[19062],"Offline-First Apps with PouchDB"," — альтернативна база даних з вбудованою синхронізацією (CouchDB protocol).",[3765,19792,19793,19798],{},[11138,19794,19797],{"href":19795,"rel":19796},"https:\u002F\u002Fwatermelondb.dev\u002F",[19062],"WatermelonDB"," — reactive offline-first база для React Native (observer pattern, fast queries).",[3765,19800,19801,19806],{},[11138,19802,19805],{"href":19803,"rel":19804},"https:\u002F\u002Fcrdt.tech\u002F",[19062],"CRDT Explained"," — conflict-free replicated data types для automatic merge без конфліктів (складніша тема).",[8173,19808,19809],{},"html pre.shiki code .su1O8, html code.shiki .su1O8{--shiki-light:#0000FF;--shiki-default:#569CD6;--shiki-dark:#569CD6}html pre.shiki code .sN1BT, html code.shiki .sN1BT{--shiki-light:#267F99;--shiki-default:#4EC9B0;--shiki-dark:#4EC9B0}html pre.shiki code .sHH4Y, html code.shiki .sHH4Y{--shiki-light:#000000;--shiki-default:#D4D4D4;--shiki-dark:#D4D4D4}html pre.shiki code .siwwj, html code.shiki .siwwj{--shiki-light:#001080;--shiki-default:#9CDCFE;--shiki-dark:#9CDCFE}html pre.shiki code .spJ8K, html code.shiki .spJ8K{--shiki-light:#008000;--shiki-default:#6A9955;--shiki-dark:#6A9955}html pre.shiki code .sbdoH, html code.shiki .sbdoH{--shiki-light:#A31515;--shiki-default:#CE9178;--shiki-dark:#CE9178}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s8xlr, html code.shiki .s8xlr{--shiki-light:#AF00DB;--shiki-default:#C586C0;--shiki-dark:#C586C0}html pre.shiki code .s-QsJ, html code.shiki .s-QsJ{--shiki-light:#0070C1;--shiki-default:#4FC1FF;--shiki-dark:#4FC1FF}html pre.shiki code .s8Opu, html code.shiki .s8Opu{--shiki-light:#795E26;--shiki-default:#DCDCAA;--shiki-dark:#DCDCAA}html pre.shiki code .sJj4R, html code.shiki .sJj4R{--shiki-light:#098658;--shiki-default:#B5CEA8;--shiki-dark:#B5CEA8}html pre.shiki code .sD7JJ, html code.shiki .sD7JJ{--shiki-light:#000000FF;--shiki-default:#D4D4D4;--shiki-dark:#D4D4D4}html pre.shiki code .sKtos, html code.shiki .sKtos{--shiki-light:#800000;--shiki-default:#569CD6;--shiki-dark:#569CD6}html pre.shiki code .sLwNe, html code.shiki .sLwNe{--shiki-light:#0451A5;--shiki-default:#9CDCFE;--shiki-dark:#9CDCFE}html pre.shiki code .s5IvJ, html code.shiki .s5IvJ{--shiki-light:#000000;--shiki-default:#C8C8C8;--shiki-dark:#C8C8C8}html pre.shiki code .se1LK, html code.shiki .se1LK{--shiki-light:#CD3131;--shiki-default:#F44747;--shiki-dark:#F44747}",{"title":3978,"searchDepth":4000,"depth":4000,"links":19811},[19812,19813,19826,19831,19838,19843,19844],{"id":3740,"depth":4000,"text":3741},{"id":3840,"depth":4000,"text":3841,"children":19814},[19815,19816,19817,19818,19819,19820,19821,19822,19823,19824,19825],{"id":3845,"depth":4020,"text":3846},{"id":3964,"depth":4020,"text":3965},{"id":4233,"depth":4020,"text":4234},{"id":4453,"depth":4020,"text":4454},{"id":4642,"depth":4020,"text":4643},{"id":4797,"depth":4020,"text":4798},{"id":5185,"depth":4020,"text":5186},{"id":5884,"depth":4020,"text":5869},{"id":6718,"depth":4020,"text":5872},{"id":7129,"depth":4020,"text":7130},{"id":7269,"depth":4020,"text":7270},{"id":7376,"depth":4000,"text":7377,"children":19827},[19828,19829,19830],{"id":10934,"depth":4020,"text":10935},{"id":11169,"depth":4020,"text":11170},{"id":11291,"depth":4020,"text":11292},{"id":11339,"depth":4000,"text":11340,"children":19832},[19833,19834,19835,19836,19837],{"id":11343,"depth":4020,"text":11344},{"id":11397,"depth":4020,"text":11398},{"id":11546,"depth":4020,"text":11547},{"id":19136,"depth":4020,"text":19137},{"id":19252,"depth":4020,"text":19253},{"id":19389,"depth":4000,"text":19390,"children":19839},[19840,19841,19842],{"id":19393,"depth":4020,"text":19394},{"id":19466,"depth":4020,"text":19467},{"id":19539,"depth":4020,"text":19540},{"id":19663,"depth":4000,"text":19664},{"id":19763,"depth":4000,"text":19764},"Як зберігати зміни без мережі, синхронізувати їх з сервером і показувати статус sync користувачу","md",null,{},{"title":3464,"description":19845},"BySjcRcVbs2zc1h8wtXIPCRxj1FjDXgZHogiGVaVNSU",[19852,19854],{"title":3460,"path":3461,"stem":3462,"description":19853,"children":-1},"Як зберігати дані на пристрої між перезапусками застосунку, коли використовувати key-value сховища та структуровані бази даних, і що вибрати для різних сценаріїв",{"title":3468,"path":3469,"stem":3470,"description":19855,"children":-1},"Дозволи (permissions), вибір зображень з бібліотеки або камери, стиснення фото та робота з локальними URI у React Native \u002F Expo",1788069967339]