diff --git a/mobile/App.tsx b/mobile/App.tsx
deleted file mode 100644
index 0329d0c..0000000
--- a/mobile/App.tsx
+++ /dev/null
@@ -1,20 +0,0 @@
-import { StatusBar } from 'expo-status-bar';
-import { StyleSheet, Text, View } from 'react-native';
-
-export default function App() {
- return (
-
- Open up App.tsx to start working on your app!
-
-
- );
-}
-
-const styles = StyleSheet.create({
- container: {
- flex: 1,
- backgroundColor: '#fff',
- alignItems: 'center',
- justifyContent: 'center',
- },
-});
diff --git a/mobile/app.json b/mobile/app.json
index 55afdac..847762c 100644
--- a/mobile/app.json
+++ b/mobile/app.json
@@ -1,34 +1,41 @@
{
"expo": {
- "name": "mobile",
- "slug": "mobile",
+ "name": "Task Team",
+ "slug": "task-team",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/icon.png",
- "userInterfaceStyle": "light",
- "newArchEnabled": true,
+ "userInterfaceStyle": "automatic",
"splash": {
"image": "./assets/splash-icon.png",
"resizeMode": "contain",
- "backgroundColor": "#ffffff"
+ "backgroundColor": "#3B82F6"
},
"ios": {
- "supportsTablet": true
+ "supportsTablet": true,
+ "bundleIdentifier": "info.hasdo.taskteam"
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png",
- "backgroundColor": "#ffffff"
+ "backgroundColor": "#3B82F6"
},
- "edgeToEdgeEnabled": true,
- "predictiveBackGestureEnabled": false
+ "package": "info.hasdo.taskteam"
},
"web": {
- "favicon": "./assets/favicon.png"
+ "bundler": "metro"
},
+ "scheme": "taskteam",
"plugins": [
"expo-router",
- "expo-secure-store"
+ "expo-secure-store",
+ [
+ "expo-notifications",
+ {
+ "icon": "./assets/icon.png",
+ "color": "#3B82F6"
+ }
+ ]
]
}
}
diff --git a/mobile/app/(tabs)/_layout.tsx b/mobile/app/(tabs)/_layout.tsx
new file mode 100644
index 0000000..56cd7bb
--- /dev/null
+++ b/mobile/app/(tabs)/_layout.tsx
@@ -0,0 +1,63 @@
+import { Tabs } from 'expo-router';
+import { Ionicons } from '@expo/vector-icons';
+
+export default function TabLayout() {
+ return (
+
+ (
+
+ ),
+ }}
+ />
+ (
+
+ ),
+ }}
+ />
+ (
+
+ ),
+ }}
+ />
+ (
+
+ ),
+ }}
+ />
+ (
+
+ ),
+ }}
+ />
+
+ );
+}
diff --git a/mobile/app/(tabs)/calendar.tsx b/mobile/app/(tabs)/calendar.tsx
new file mode 100644
index 0000000..27309d0
--- /dev/null
+++ b/mobile/app/(tabs)/calendar.tsx
@@ -0,0 +1,264 @@
+import { useState, useEffect, useCallback } from 'react';
+import {
+ View,
+ Text,
+ StyleSheet,
+ ScrollView,
+ RefreshControl,
+ TouchableOpacity,
+ Alert,
+} from 'react-native';
+import { Ionicons } from '@expo/vector-icons';
+import { useAuthContext } from '../../lib/AuthContext';
+import * as api from '../../lib/api';
+
+const DAYS = ['Po', 'Ut', 'St', 'Ct', 'Pa', 'So', 'Ne'];
+const MONTHS = [
+ 'Leden', 'Unor', 'Brezen', 'Duben', 'Kveten', 'Cerven',
+ 'Cervenec', 'Srpen', 'Zari', 'Rijen', 'Listopad', 'Prosinec',
+];
+
+function getDaysInMonth(year: number, month: number) {
+ return new Date(year, month + 1, 0).getDate();
+}
+
+function getFirstDayOfMonth(year: number, month: number) {
+ const day = new Date(year, month, 1).getDay();
+ return day === 0 ? 6 : day - 1; // Monday = 0
+}
+
+export default function CalendarScreen() {
+ const { token } = useAuthContext();
+ const [tasks, setTasks] = useState([]);
+ const [refreshing, setRefreshing] = useState(false);
+ const [currentDate, setCurrentDate] = useState(new Date());
+ const [selectedDate, setSelectedDate] = useState(null);
+
+ const year = currentDate.getFullYear();
+ const month = currentDate.getMonth();
+
+ const loadTasks = useCallback(async () => {
+ if (!token) return;
+ try {
+ const res = await api.getTasks(token);
+ setTasks(res.data || []);
+ } catch (err: any) {
+ Alert.alert('Chyba', err.message);
+ }
+ }, [token]);
+
+ useEffect(() => {
+ loadTasks();
+ }, [loadTasks]);
+
+ const onRefresh = useCallback(async () => {
+ setRefreshing(true);
+ await loadTasks();
+ setRefreshing(false);
+ }, [loadTasks]);
+
+ const prevMonth = () => {
+ setCurrentDate(new Date(year, month - 1, 1));
+ setSelectedDate(null);
+ };
+
+ const nextMonth = () => {
+ setCurrentDate(new Date(year, month + 1, 1));
+ setSelectedDate(null);
+ };
+
+ const daysInMonth = getDaysInMonth(year, month);
+ const firstDay = getFirstDayOfMonth(year, month);
+
+ const tasksByDate: Record = {};
+ tasks.forEach((t) => {
+ if (t.due_date) {
+ const d = t.due_date.substring(0, 10);
+ if (!tasksByDate[d]) tasksByDate[d] = [];
+ tasksByDate[d].push(t);
+ }
+ });
+
+ const today = new Date().toISOString().substring(0, 10);
+
+ const selectedTasks = selectedDate ? tasksByDate[selectedDate] || [] : [];
+
+ return (
+
+ }
+ >
+ {/* Month navigator */}
+
+
+
+
+
+ {MONTHS[month]} {year}
+
+
+
+
+
+
+ {/* Day headers */}
+
+ {DAYS.map((d) => (
+
+ {d}
+
+ ))}
+
+
+ {/* Calendar grid */}
+
+ {Array.from({ length: firstDay }).map((_, i) => (
+
+ ))}
+ {Array.from({ length: daysInMonth }).map((_, i) => {
+ const day = i + 1;
+ const dateStr = `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
+ const hasTasks = !!tasksByDate[dateStr];
+ const isToday = dateStr === today;
+ const isSelected = dateStr === selectedDate;
+
+ return (
+ setSelectedDate(dateStr)}
+ >
+
+ {day}
+
+ {hasTasks && (
+
+ )}
+
+ );
+ })}
+
+
+ {/* Selected date tasks */}
+ {selectedDate && (
+
+
+ Ukoly na {selectedDate}
+
+ {selectedTasks.length === 0 ? (
+ Zadne ukoly
+ ) : (
+ selectedTasks.map((t) => (
+
+
+
+ {t.title}
+
+
+ ))
+ )}
+
+ )}
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: { flex: 1, backgroundColor: '#F8FAFC' },
+ monthNav: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'space-between',
+ padding: 16,
+ backgroundColor: '#fff',
+ },
+ navBtn: { padding: 8 },
+ monthTitle: { fontSize: 18, fontWeight: '700', color: '#1E293B' },
+ dayHeaders: {
+ flexDirection: 'row',
+ backgroundColor: '#fff',
+ paddingBottom: 8,
+ borderBottomWidth: 1,
+ borderBottomColor: '#E2E8F0',
+ },
+ dayHeader: {
+ flex: 1,
+ textAlign: 'center',
+ fontSize: 12,
+ fontWeight: '600',
+ color: '#64748B',
+ },
+ grid: {
+ flexDirection: 'row',
+ flexWrap: 'wrap',
+ backgroundColor: '#fff',
+ padding: 4,
+ },
+ dayCell: {
+ width: '14.28%',
+ aspectRatio: 1,
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+ todayCell: {
+ backgroundColor: '#EFF6FF',
+ borderRadius: 20,
+ },
+ selectedCell: {
+ backgroundColor: '#3B82F6',
+ borderRadius: 20,
+ },
+ dayText: { fontSize: 15, color: '#1E293B' },
+ todayText: { color: '#3B82F6', fontWeight: '700' },
+ selectedText: { color: '#fff', fontWeight: '700' },
+ dot: {
+ width: 5,
+ height: 5,
+ borderRadius: 3,
+ backgroundColor: '#3B82F6',
+ marginTop: 2,
+ },
+ tasksSection: {
+ margin: 12,
+ padding: 16,
+ backgroundColor: '#fff',
+ borderRadius: 12,
+ },
+ tasksSectionTitle: { fontSize: 16, fontWeight: '600', color: '#1E293B', marginBottom: 12 },
+ noTasks: { color: '#94A3B8', fontSize: 14 },
+ taskItem: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ gap: 10,
+ paddingVertical: 8,
+ borderBottomWidth: 1,
+ borderBottomColor: '#F1F5F9',
+ },
+ taskItemText: { fontSize: 14, color: '#1E293B', flex: 1 },
+});
diff --git a/mobile/app/(tabs)/chat.tsx b/mobile/app/(tabs)/chat.tsx
new file mode 100644
index 0000000..5da5e6f
--- /dev/null
+++ b/mobile/app/(tabs)/chat.tsx
@@ -0,0 +1,217 @@
+import { useState, useRef, useCallback } from 'react';
+import {
+ View,
+ Text,
+ TextInput,
+ FlatList,
+ TouchableOpacity,
+ StyleSheet,
+ KeyboardAvoidingView,
+ Platform,
+ ActivityIndicator,
+ Alert,
+} from 'react-native';
+import { Ionicons } from '@expo/vector-icons';
+import { useAuthContext } from '../../lib/AuthContext';
+import * as api from '../../lib/api';
+
+type Message = {
+ id: string;
+ role: 'user' | 'assistant';
+ content: string;
+ timestamp: Date;
+};
+
+export default function ChatScreen() {
+ const { token } = useAuthContext();
+ const [messages, setMessages] = useState([
+ {
+ id: '0',
+ role: 'assistant',
+ content: 'Ahoj! Jsem vas AI asistent pro Task Team. Mohu vam pomoci s ukoly, planovani a organizaci. Na co se chcete zeptat?',
+ timestamp: new Date(),
+ },
+ ]);
+ const [input, setInput] = useState('');
+ const [sending, setSending] = useState(false);
+ const flatListRef = useRef(null);
+
+ const sendMessage = useCallback(async () => {
+ if (!input.trim() || !token || sending) return;
+
+ const userMsg: Message = {
+ id: Date.now().toString(),
+ role: 'user',
+ content: input.trim(),
+ timestamp: new Date(),
+ };
+
+ setMessages((prev) => [...prev, userMsg]);
+ setInput('');
+ setSending(true);
+
+ try {
+ const res = await api.sendChatMessage(token, userMsg.content);
+ const aiMsg: Message = {
+ id: (Date.now() + 1).toString(),
+ role: 'assistant',
+ content: res.data?.reply || 'Omlouvam se, nepodarilo se zpracovat odpoved.',
+ timestamp: new Date(),
+ };
+ setMessages((prev) => [...prev, aiMsg]);
+ } catch (err: any) {
+ const errMsg: Message = {
+ id: (Date.now() + 1).toString(),
+ role: 'assistant',
+ content: `Chyba: ${err.message}`,
+ timestamp: new Date(),
+ };
+ setMessages((prev) => [...prev, errMsg]);
+ } finally {
+ setSending(false);
+ }
+ }, [input, token, sending]);
+
+ const renderMessage = ({ item }: { item: Message }) => {
+ const isUser = item.role === 'user';
+ return (
+
+ {!isUser && (
+
+
+
+ )}
+
+
+ {item.content}
+
+
+ {item.timestamp.toLocaleTimeString('cs-CZ', {
+ hour: '2-digit',
+ minute: '2-digit',
+ })}
+
+
+
+ );
+ };
+
+ return (
+
+ item.id}
+ renderItem={renderMessage}
+ contentContainerStyle={styles.listContent}
+ onContentSizeChange={() =>
+ flatListRef.current?.scrollToEnd({ animated: true })
+ }
+ />
+
+
+
+
+ {sending ? (
+
+ ) : (
+
+ )}
+
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: { flex: 1, backgroundColor: '#F8FAFC' },
+ listContent: { padding: 12, paddingBottom: 4 },
+ msgRow: { flexDirection: 'row', marginBottom: 12, maxWidth: '85%' },
+ msgRowUser: { alignSelf: 'flex-end' },
+ msgRowAi: { alignSelf: 'flex-start' },
+ avatar: {
+ width: 32,
+ height: 32,
+ borderRadius: 16,
+ backgroundColor: '#EFF6FF',
+ alignItems: 'center',
+ justifyContent: 'center',
+ marginRight: 8,
+ marginTop: 4,
+ },
+ bubble: { borderRadius: 16, padding: 12, maxWidth: '100%' },
+ bubbleUser: {
+ backgroundColor: '#3B82F6',
+ borderBottomRightRadius: 4,
+ },
+ bubbleAi: {
+ backgroundColor: '#fff',
+ borderBottomLeftRadius: 4,
+ borderWidth: 1,
+ borderColor: '#E2E8F0',
+ },
+ bubbleText: { fontSize: 15, lineHeight: 21, color: '#1E293B' },
+ timestamp: { fontSize: 10, color: '#94A3B8', marginTop: 4, textAlign: 'right' },
+ inputBar: {
+ flexDirection: 'row',
+ alignItems: 'flex-end',
+ padding: 12,
+ backgroundColor: '#fff',
+ borderTopWidth: 1,
+ borderTopColor: '#E2E8F0',
+ },
+ input: {
+ flex: 1,
+ borderWidth: 1,
+ borderColor: '#E2E8F0',
+ borderRadius: 20,
+ paddingHorizontal: 16,
+ paddingVertical: 10,
+ fontSize: 15,
+ maxHeight: 100,
+ backgroundColor: '#F8FAFC',
+ },
+ sendBtn: {
+ width: 42,
+ height: 42,
+ borderRadius: 21,
+ backgroundColor: '#3B82F6',
+ alignItems: 'center',
+ justifyContent: 'center',
+ marginLeft: 8,
+ },
+ sendBtnDisabled: { backgroundColor: '#94A3B8' },
+});
diff --git a/mobile/app/(tabs)/goals.tsx b/mobile/app/(tabs)/goals.tsx
new file mode 100644
index 0000000..d27c901
--- /dev/null
+++ b/mobile/app/(tabs)/goals.tsx
@@ -0,0 +1,162 @@
+import { useState, useEffect, useCallback } from 'react';
+import {
+ View,
+ Text,
+ FlatList,
+ StyleSheet,
+ RefreshControl,
+ Alert,
+} from 'react-native';
+import { Ionicons } from '@expo/vector-icons';
+import { useAuthContext } from '../../lib/AuthContext';
+import * as api from '../../lib/api';
+
+export default function GoalsScreen() {
+ const { token } = useAuthContext();
+ const [goals, setGoals] = useState([]);
+ const [refreshing, setRefreshing] = useState(false);
+
+ const loadGoals = useCallback(async () => {
+ if (!token) return;
+ try {
+ const res = await api.getGoals(token);
+ setGoals(res.data || []);
+ } catch (err: any) {
+ Alert.alert('Chyba', err.message);
+ }
+ }, [token]);
+
+ useEffect(() => {
+ loadGoals();
+ }, [loadGoals]);
+
+ const onRefresh = useCallback(async () => {
+ setRefreshing(true);
+ await loadGoals();
+ setRefreshing(false);
+ }, [loadGoals]);
+
+ const renderGoal = ({ item }: { item: any }) => {
+ const progress = item.progress || 0;
+ const total = item.target || 100;
+ const pct = Math.min(Math.round((progress / total) * 100), 100);
+
+ return (
+
+
+
+ = 100 ? 'trophy' : 'flag-outline'}
+ size={24}
+ color={pct >= 100 ? '#F59E0B' : '#3B82F6'}
+ />
+
+
+ {item.title}
+ {item.description && (
+
+ {item.description}
+
+ )}
+
+ {pct}%
+
+
+
+ = 100 ? '#22C55E' : pct >= 50 ? '#3B82F6' : '#F59E0B',
+ },
+ ]}
+ />
+
+
+
+
+ {progress} / {total}
+
+ {item.deadline && (
+
+ {' '}
+ {new Date(item.deadline).toLocaleDateString('cs-CZ')}
+
+ )}
+
+
+ );
+ };
+
+ return (
+
+ item.id?.toString()}
+ renderItem={renderGoal}
+ refreshControl={
+
+ }
+ contentContainerStyle={styles.listContent}
+ ListEmptyComponent={
+
+
+ Zatim zadne cile
+
+ Vytvorte cile ve webove aplikaci
+
+
+ }
+ />
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: { flex: 1, backgroundColor: '#F8FAFC' },
+ listContent: { padding: 12, paddingBottom: 20 },
+ goalCard: {
+ backgroundColor: '#fff',
+ borderRadius: 12,
+ padding: 16,
+ marginBottom: 12,
+ shadowColor: '#000',
+ shadowOffset: { width: 0, height: 1 },
+ shadowOpacity: 0.05,
+ shadowRadius: 3,
+ elevation: 2,
+ },
+ goalHeader: { flexDirection: 'row', alignItems: 'center', marginBottom: 12 },
+ goalIcon: {
+ width: 40,
+ height: 40,
+ borderRadius: 10,
+ backgroundColor: '#EFF6FF',
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+ goalInfo: { flex: 1, marginLeft: 12 },
+ goalTitle: { fontSize: 16, fontWeight: '600', color: '#1E293B' },
+ goalDesc: { fontSize: 13, color: '#64748B', marginTop: 2 },
+ goalPct: { fontSize: 18, fontWeight: '700', color: '#3B82F6' },
+ progressBarBg: {
+ height: 8,
+ borderRadius: 4,
+ backgroundColor: '#E2E8F0',
+ },
+ progressBarFill: {
+ height: 8,
+ borderRadius: 4,
+ },
+ goalFooter: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ marginTop: 8,
+ },
+ goalStat: { fontSize: 12, color: '#64748B' },
+ goalDeadline: { fontSize: 12, color: '#94A3B8' },
+ empty: { alignItems: 'center', marginTop: 60 },
+ emptyText: { color: '#94A3B8', fontSize: 16, marginTop: 12 },
+ emptySubtext: { color: '#CBD5E1', fontSize: 13, marginTop: 4 },
+});
diff --git a/mobile/app/(tabs)/index.tsx b/mobile/app/(tabs)/index.tsx
new file mode 100644
index 0000000..ed68e62
--- /dev/null
+++ b/mobile/app/(tabs)/index.tsx
@@ -0,0 +1,329 @@
+import { useState, useEffect, useCallback } from 'react';
+import {
+ View,
+ Text,
+ FlatList,
+ TouchableOpacity,
+ StyleSheet,
+ RefreshControl,
+ Alert,
+ TextInput,
+ Modal,
+} from 'react-native';
+import { Ionicons } from '@expo/vector-icons';
+import { useAuthContext } from '../../lib/AuthContext';
+import * as api from '../../lib/api';
+
+const PRIORITY_COLORS: Record = {
+ high: '#EF4444',
+ medium: '#F59E0B',
+ low: '#22C55E',
+};
+
+const STATUS_ICONS: Record = {
+ todo: 'ellipse-outline',
+ in_progress: 'time-outline',
+ done: 'checkmark-circle',
+};
+
+export default function TasksScreen() {
+ const { token } = useAuthContext();
+ const [tasks, setTasks] = useState([]);
+ const [groups, setGroups] = useState([]);
+ const [refreshing, setRefreshing] = useState(false);
+ const [showAdd, setShowAdd] = useState(false);
+ const [newTitle, setNewTitle] = useState('');
+ const [filter, setFilter] = useState('all');
+
+ const loadData = useCallback(async () => {
+ if (!token) return;
+ try {
+ const [tasksRes, groupsRes] = await Promise.all([
+ api.getTasks(token),
+ api.getGroups(token),
+ ]);
+ setTasks(tasksRes.data || []);
+ setGroups(groupsRes.data || []);
+ } catch (err: any) {
+ Alert.alert('Chyba', err.message);
+ }
+ }, [token]);
+
+ useEffect(() => {
+ loadData();
+ }, [loadData]);
+
+ const onRefresh = useCallback(async () => {
+ setRefreshing(true);
+ await loadData();
+ setRefreshing(false);
+ }, [loadData]);
+
+ const addTask = async () => {
+ if (!newTitle.trim() || !token) return;
+ try {
+ await api.createTask(token, { title: newTitle.trim() });
+ setNewTitle('');
+ setShowAdd(false);
+ await loadData();
+ } catch (err: any) {
+ Alert.alert('Chyba', err.message);
+ }
+ };
+
+ const toggleTask = async (task: any) => {
+ if (!token) return;
+ const newStatus = task.status === 'done' ? 'todo' : 'done';
+ try {
+ await api.updateTask(token, task.id, { status: newStatus });
+ await loadData();
+ } catch (err: any) {
+ Alert.alert('Chyba', err.message);
+ }
+ };
+
+ const filteredTasks =
+ filter === 'all' ? tasks : tasks.filter((t) => t.status === filter);
+
+ const getGroupColor = (groupId: string) => {
+ const group = groups.find((g) => g.id === groupId);
+ return group?.color || '#64748B';
+ };
+
+ const renderTask = ({ item }: { item: any }) => (
+ toggleTask(item)}
+ activeOpacity={0.7}
+ >
+
+
+
+
+ {item.title}
+
+ {item.group_name && (
+
+
+ {item.group_name}
+
+
+ )}
+
+
+ {item.priority && (
+
+ )}
+
+ );
+
+ return (
+
+ {/* Filter bar */}
+
+ {['all', 'todo', 'in_progress', 'done'].map((f) => (
+ setFilter(f)}
+ >
+
+ {f === 'all'
+ ? 'Vse'
+ : f === 'todo'
+ ? 'K provedeni'
+ : f === 'in_progress'
+ ? 'Rozpracovano'
+ : 'Hotovo'}
+
+
+ ))}
+
+
+ {/* Task list */}
+ item.id?.toString()}
+ renderItem={renderTask}
+ refreshControl={
+
+ }
+ contentContainerStyle={styles.listContent}
+ ListEmptyComponent={
+
+
+ Zatim zadne ukoly
+
+ }
+ />
+
+ {/* FAB */}
+ setShowAdd(true)}
+ >
+
+
+
+ {/* Add task modal */}
+
+
+
+ Novy ukol
+
+
+ {
+ setShowAdd(false);
+ setNewTitle('');
+ }}
+ >
+ Zrusit
+
+
+ Pridat
+
+
+
+
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: { flex: 1, backgroundColor: '#F8FAFC' },
+ filterBar: {
+ flexDirection: 'row',
+ padding: 12,
+ gap: 8,
+ backgroundColor: '#fff',
+ borderBottomWidth: 1,
+ borderBottomColor: '#E2E8F0',
+ },
+ filterBtn: {
+ paddingHorizontal: 12,
+ paddingVertical: 6,
+ borderRadius: 16,
+ backgroundColor: '#F1F5F9',
+ },
+ filterBtnActive: { backgroundColor: '#3B82F6' },
+ filterText: { fontSize: 13, color: '#64748B' },
+ filterTextActive: { color: '#fff', fontWeight: '600' },
+ listContent: { padding: 12, paddingBottom: 80 },
+ taskCard: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'space-between',
+ backgroundColor: '#fff',
+ borderRadius: 12,
+ padding: 16,
+ marginBottom: 8,
+ shadowColor: '#000',
+ shadowOffset: { width: 0, height: 1 },
+ shadowOpacity: 0.05,
+ shadowRadius: 3,
+ elevation: 2,
+ },
+ taskLeft: { flexDirection: 'row', alignItems: 'center', flex: 1 },
+ taskInfo: { marginLeft: 12, flex: 1 },
+ taskTitle: { fontSize: 15, color: '#1E293B', fontWeight: '500' },
+ taskDone: {
+ textDecorationLine: 'line-through',
+ color: '#94A3B8',
+ },
+ groupBadge: { marginTop: 4, paddingHorizontal: 8, paddingVertical: 2, borderRadius: 8, alignSelf: 'flex-start' },
+ groupBadgeText: { fontSize: 11, fontWeight: '600' },
+ priorityDot: { width: 10, height: 10, borderRadius: 5 },
+ empty: { alignItems: 'center', marginTop: 60 },
+ emptyText: { color: '#94A3B8', fontSize: 16, marginTop: 12 },
+ fab: {
+ position: 'absolute',
+ right: 20,
+ bottom: 20,
+ width: 56,
+ height: 56,
+ borderRadius: 28,
+ backgroundColor: '#3B82F6',
+ alignItems: 'center',
+ justifyContent: 'center',
+ shadowColor: '#3B82F6',
+ shadowOffset: { width: 0, height: 4 },
+ shadowOpacity: 0.3,
+ shadowRadius: 8,
+ elevation: 6,
+ },
+ modalOverlay: {
+ flex: 1,
+ backgroundColor: 'rgba(0,0,0,0.4)',
+ justifyContent: 'flex-end',
+ },
+ modalContent: {
+ backgroundColor: '#fff',
+ borderTopLeftRadius: 20,
+ borderTopRightRadius: 20,
+ padding: 24,
+ paddingBottom: 40,
+ },
+ modalTitle: { fontSize: 18, fontWeight: '700', color: '#1E293B', marginBottom: 16 },
+ input: {
+ borderWidth: 1,
+ borderColor: '#E2E8F0',
+ borderRadius: 12,
+ padding: 14,
+ fontSize: 16,
+ backgroundColor: '#F8FAFC',
+ },
+ modalActions: {
+ flexDirection: 'row',
+ justifyContent: 'flex-end',
+ gap: 12,
+ marginTop: 16,
+ },
+ cancelBtn: { paddingHorizontal: 20, paddingVertical: 10 },
+ cancelText: { color: '#64748B', fontSize: 15 },
+ addBtn: {
+ backgroundColor: '#3B82F6',
+ paddingHorizontal: 24,
+ paddingVertical: 10,
+ borderRadius: 10,
+ },
+ addBtnText: { color: '#fff', fontSize: 15, fontWeight: '600' },
+});
diff --git a/mobile/app/(tabs)/settings.tsx b/mobile/app/(tabs)/settings.tsx
new file mode 100644
index 0000000..9bb5621
--- /dev/null
+++ b/mobile/app/(tabs)/settings.tsx
@@ -0,0 +1,220 @@
+import { useState } from 'react';
+import {
+ View,
+ Text,
+ StyleSheet,
+ ScrollView,
+ TouchableOpacity,
+ Switch,
+ Alert,
+} from 'react-native';
+import { Ionicons } from '@expo/vector-icons';
+import { useAuthContext } from '../../lib/AuthContext';
+import Constants from 'expo-constants';
+
+export default function SettingsScreen() {
+ const { user, logout } = useAuthContext();
+ const [darkMode, setDarkMode] = useState(false);
+ const [notifications, setNotifications] = useState(true);
+ const [language, setLanguage] = useState<'cs' | 'en'>('cs');
+
+ const handleLogout = () => {
+ Alert.alert(
+ 'Odhlaseni',
+ 'Opravdu se chcete odhlasit?',
+ [
+ { text: 'Zrusit', style: 'cancel' },
+ {
+ text: 'Odhlasit',
+ style: 'destructive',
+ onPress: logout,
+ },
+ ],
+ );
+ };
+
+ const renderSection = (title: string, children: React.ReactNode) => (
+
+ {title}
+ {children}
+
+ );
+
+ const renderRow = (
+ icon: string,
+ label: string,
+ right?: React.ReactNode,
+ onPress?: () => void,
+ ) => (
+
+
+
+ {label}
+
+ {right || (onPress && )}
+
+ );
+
+ return (
+
+ {/* User card */}
+
+
+
+ {(user?.name || 'U')[0].toUpperCase()}
+
+
+
+ {user?.name || 'Uzivatel'}
+ {user?.email || ''}
+
+
+
+ {renderSection('Predvolby', (
+ <>
+ {renderRow(
+ 'moon-outline',
+ 'Tmavy rezim',
+ ,
+ )}
+ {renderRow(
+ 'notifications-outline',
+ 'Oznameni',
+ ,
+ )}
+ {renderRow(
+ 'language-outline',
+ 'Jazyk',
+ setLanguage(language === 'cs' ? 'en' : 'cs')}
+ >
+
+ {language === 'cs' ? 'Cestina' : 'English'}
+
+ ,
+ )}
+ >
+ ))}
+
+ {renderSection('Ucet', (
+ <>
+ {renderRow('person-outline', 'Upravit profil', undefined, () =>
+ Alert.alert('Info', 'Bude k dispozici brzy'),
+ )}
+ {renderRow('lock-closed-outline', 'Zmenit heslo', undefined, () =>
+ Alert.alert('Info', 'Bude k dispozici brzy'),
+ )}
+ >
+ ))}
+
+ {renderSection('Informace', (
+ <>
+ {renderRow('information-circle-outline', 'Verze', (
+
+ {Constants.expoConfig?.version || '1.0.0'}
+
+ ))}
+ {renderRow('document-text-outline', 'Podminky pouziti', undefined, () =>
+ Alert.alert('Info', 'Bude k dispozici brzy'),
+ )}
+ >
+ ))}
+
+ {/* Logout */}
+
+
+ Odhlasit se
+
+
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: { flex: 1, backgroundColor: '#F8FAFC' },
+ userCard: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ backgroundColor: '#fff',
+ padding: 20,
+ margin: 12,
+ borderRadius: 12,
+ shadowColor: '#000',
+ shadowOffset: { width: 0, height: 1 },
+ shadowOpacity: 0.05,
+ shadowRadius: 3,
+ elevation: 2,
+ },
+ userAvatar: {
+ width: 56,
+ height: 56,
+ borderRadius: 28,
+ backgroundColor: '#3B82F6',
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+ userAvatarText: { color: '#fff', fontSize: 22, fontWeight: '700' },
+ userInfo: { marginLeft: 16, flex: 1 },
+ userName: { fontSize: 18, fontWeight: '600', color: '#1E293B' },
+ userEmail: { fontSize: 14, color: '#64748B', marginTop: 2 },
+ section: { marginTop: 12, marginHorizontal: 12 },
+ sectionTitle: {
+ fontSize: 13,
+ fontWeight: '600',
+ color: '#64748B',
+ textTransform: 'uppercase',
+ marginBottom: 6,
+ marginLeft: 4,
+ },
+ sectionContent: {
+ backgroundColor: '#fff',
+ borderRadius: 12,
+ overflow: 'hidden',
+ },
+ row: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'space-between',
+ paddingHorizontal: 16,
+ paddingVertical: 14,
+ borderBottomWidth: 1,
+ borderBottomColor: '#F1F5F9',
+ },
+ rowLeft: { flexDirection: 'row', alignItems: 'center', gap: 12 },
+ rowLabel: { fontSize: 15, color: '#1E293B' },
+ langToggle: {
+ backgroundColor: '#F1F5F9',
+ paddingHorizontal: 12,
+ paddingVertical: 4,
+ borderRadius: 8,
+ },
+ langText: { fontSize: 13, color: '#3B82F6', fontWeight: '600' },
+ versionText: { fontSize: 14, color: '#94A3B8' },
+ logoutBtn: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'center',
+ gap: 8,
+ marginTop: 24,
+ marginHorizontal: 12,
+ paddingVertical: 14,
+ backgroundColor: '#FEF2F2',
+ borderRadius: 12,
+ },
+ logoutText: { color: '#EF4444', fontSize: 16, fontWeight: '600' },
+});
diff --git a/mobile/app/_layout.tsx b/mobile/app/_layout.tsx
new file mode 100644
index 0000000..27cc906
--- /dev/null
+++ b/mobile/app/_layout.tsx
@@ -0,0 +1,32 @@
+import { useEffect } from 'react';
+import { Slot, useRouter, useSegments } from 'expo-router';
+import { StatusBar } from 'expo-status-bar';
+import { AuthProvider, useAuthContext } from '../lib/AuthContext';
+
+function AuthGate() {
+ const { token, loading } = useAuthContext();
+ const segments = useSegments();
+ const router = useRouter();
+
+ useEffect(() => {
+ if (loading) return;
+ const inAuthGroup = segments[0] === 'login';
+
+ if (!token && !inAuthGroup) {
+ router.replace('/login');
+ } else if (token && inAuthGroup) {
+ router.replace('/');
+ }
+ }, [token, loading, segments]);
+
+ return ;
+}
+
+export default function RootLayout() {
+ return (
+
+
+
+
+ );
+}
diff --git a/mobile/app/login.tsx b/mobile/app/login.tsx
new file mode 100644
index 0000000..c55080b
--- /dev/null
+++ b/mobile/app/login.tsx
@@ -0,0 +1,256 @@
+import { useState } from 'react';
+import {
+ View,
+ Text,
+ TextInput,
+ TouchableOpacity,
+ StyleSheet,
+ KeyboardAvoidingView,
+ Platform,
+ ScrollView,
+ Alert,
+ ActivityIndicator,
+} from 'react-native';
+import { Ionicons } from '@expo/vector-icons';
+import { useAuthContext } from '../lib/AuthContext';
+
+export default function LoginScreen() {
+ const { login, register } = useAuthContext();
+ const [mode, setMode] = useState<'login' | 'register'>('login');
+ const [email, setEmail] = useState('');
+ const [name, setName] = useState('');
+ const [password, setPassword] = useState('');
+ const [showPassword, setShowPassword] = useState(false);
+ const [loading, setLoading] = useState(false);
+
+ const handleSubmit = async () => {
+ if (!email.trim() || !password.trim()) {
+ Alert.alert('Chyba', 'Vyplnte vsechna pole');
+ return;
+ }
+ if (mode === 'register' && !name.trim()) {
+ Alert.alert('Chyba', 'Vyplnte jmeno');
+ return;
+ }
+
+ setLoading(true);
+ try {
+ if (mode === 'login') {
+ await login(email.trim(), password);
+ } else {
+ await register(email.trim(), name.trim(), password);
+ }
+ } catch (err: any) {
+ Alert.alert('Chyba', err.message || 'Nepodarilo se prihlasit');
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ return (
+
+
+ {/* Logo */}
+
+
+
+
+ Task Team
+
+ Spravujte ukoly, cile a tymovou spolupraci
+
+
+
+ {/* Form */}
+
+ {/* Mode toggle */}
+
+ setMode('login')}
+ >
+
+ Prihlaseni
+
+
+ setMode('register')}
+ >
+
+ Registrace
+
+
+
+
+ {mode === 'register' && (
+
+
+
+
+ )}
+
+
+
+
+
+
+
+
+
+ setShowPassword(!showPassword)}
+ style={styles.eyeBtn}
+ >
+
+
+
+
+
+ {loading ? (
+
+ ) : (
+
+ {mode === 'login' ? 'Prihlasit se' : 'Zaregistrovat se'}
+
+ )}
+
+
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: { flex: 1, backgroundColor: '#F8FAFC' },
+ scrollContent: {
+ flexGrow: 1,
+ justifyContent: 'center',
+ padding: 24,
+ },
+ logoSection: { alignItems: 'center', marginBottom: 40 },
+ logoCircle: {
+ width: 80,
+ height: 80,
+ borderRadius: 20,
+ backgroundColor: '#3B82F6',
+ alignItems: 'center',
+ justifyContent: 'center',
+ marginBottom: 16,
+ },
+ appName: { fontSize: 28, fontWeight: '800', color: '#1E293B' },
+ appDesc: {
+ fontSize: 15,
+ color: '#64748B',
+ textAlign: 'center',
+ marginTop: 8,
+ },
+ form: {},
+ modeToggle: {
+ flexDirection: 'row',
+ backgroundColor: '#E2E8F0',
+ borderRadius: 12,
+ padding: 4,
+ marginBottom: 24,
+ },
+ modeBtn: {
+ flex: 1,
+ paddingVertical: 10,
+ borderRadius: 10,
+ alignItems: 'center',
+ },
+ modeBtnActive: { backgroundColor: '#fff' },
+ modeBtnText: { fontSize: 15, color: '#64748B', fontWeight: '500' },
+ modeBtnTextActive: { color: '#3B82F6', fontWeight: '700' },
+ inputGroup: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ backgroundColor: '#fff',
+ borderRadius: 12,
+ borderWidth: 1,
+ borderColor: '#E2E8F0',
+ marginBottom: 12,
+ paddingHorizontal: 14,
+ },
+ inputIcon: { marginRight: 10 },
+ input: {
+ flex: 1,
+ paddingVertical: 14,
+ fontSize: 16,
+ color: '#1E293B',
+ },
+ eyeBtn: { padding: 4 },
+ submitBtn: {
+ backgroundColor: '#3B82F6',
+ borderRadius: 12,
+ paddingVertical: 16,
+ alignItems: 'center',
+ marginTop: 8,
+ shadowColor: '#3B82F6',
+ shadowOffset: { width: 0, height: 4 },
+ shadowOpacity: 0.2,
+ shadowRadius: 8,
+ elevation: 4,
+ },
+ submitBtnDisabled: { backgroundColor: '#94A3B8' },
+ submitBtnText: { color: '#fff', fontSize: 17, fontWeight: '700' },
+});
diff --git a/mobile/index.ts b/mobile/index.ts
index 1d6e981..5b83418 100644
--- a/mobile/index.ts
+++ b/mobile/index.ts
@@ -1,8 +1 @@
-import { registerRootComponent } from 'expo';
-
-import App from './App';
-
-// registerRootComponent calls AppRegistry.registerComponent('main', () => App);
-// It also ensures that whether you load the app in Expo Go or in a native build,
-// the environment is set up appropriately
-registerRootComponent(App);
+import 'expo-router/entry';
diff --git a/mobile/lib/AuthContext.tsx b/mobile/lib/AuthContext.tsx
new file mode 100644
index 0000000..20dae10
--- /dev/null
+++ b/mobile/lib/AuthContext.tsx
@@ -0,0 +1,17 @@
+import React, { createContext, useContext } from 'react';
+import { useAuth } from './useAuth';
+
+type AuthContextType = ReturnType;
+
+const AuthContext = createContext(null);
+
+export function AuthProvider({ children }: { children: React.ReactNode }) {
+ const auth = useAuth();
+ return {children};
+}
+
+export function useAuthContext(): AuthContextType {
+ const ctx = useContext(AuthContext);
+ if (!ctx) throw new Error('useAuthContext must be used within AuthProvider');
+ return ctx;
+}
diff --git a/mobile/lib/api.ts b/mobile/lib/api.ts
new file mode 100644
index 0000000..aff15d4
--- /dev/null
+++ b/mobile/lib/api.ts
@@ -0,0 +1,64 @@
+const API_BASE = 'https://api.hasdo.info';
+
+export async function apiFetch(
+ path: string,
+ opts: { method?: string; body?: any; token?: string } = {}
+): Promise {
+ const headers: Record = { 'Content-Type': 'application/json' };
+ if (opts.token) headers['Authorization'] = `Bearer ${opts.token}`;
+
+ const res = await fetch(`${API_BASE}${path}`, {
+ method: opts.method || 'GET',
+ headers,
+ body: opts.body ? JSON.stringify(opts.body) : undefined,
+ });
+
+ if (!res.ok) {
+ const err = await res.json().catch(() => ({ message: `HTTP ${res.status}` }));
+ throw new Error(err.message || `HTTP ${res.status}`);
+ }
+
+ return res.json();
+}
+
+// Auth
+export const login = (data: { email: string; password: string }) =>
+ apiFetch<{ data: { token: string; user: any } }>('/api/v1/auth/login', {
+ method: 'POST',
+ body: data,
+ });
+
+export const register = (data: { email: string; name: string; password: string }) =>
+ apiFetch<{ data: { token: string; user: any } }>('/api/v1/auth/register', {
+ method: 'POST',
+ body: data,
+ });
+
+// Tasks
+export const getTasks = (token: string) =>
+ apiFetch<{ data: any[] }>('/api/v1/tasks', { token });
+
+export const createTask = (token: string, data: any) =>
+ apiFetch<{ data: any }>('/api/v1/tasks', { method: 'POST', body: data, token });
+
+export const updateTask = (token: string, id: string, data: any) =>
+ apiFetch<{ data: any }>(`/api/v1/tasks/${id}`, { method: 'PUT', body: data, token });
+
+export const deleteTask = (token: string, id: string) =>
+ apiFetch(`/api/v1/tasks/${id}`, { method: 'DELETE', token });
+
+// Groups
+export const getGroups = (token: string) =>
+ apiFetch<{ data: any[] }>('/api/v1/groups', { token });
+
+// Goals
+export const getGoals = (token: string) =>
+ apiFetch<{ data: any[] }>('/api/v1/goals', { token });
+
+// Chat
+export const sendChatMessage = (token: string, message: string) =>
+ apiFetch<{ data: { reply: string } }>('/api/v1/chat', {
+ method: 'POST',
+ body: { message },
+ token,
+ });
diff --git a/mobile/lib/auth.ts b/mobile/lib/auth.ts
new file mode 100644
index 0000000..84afc95
--- /dev/null
+++ b/mobile/lib/auth.ts
@@ -0,0 +1,60 @@
+import * as SecureStore from 'expo-secure-store';
+import { Platform } from 'react-native';
+
+const TOKEN_KEY = 'taskteam_token';
+const USER_KEY = 'taskteam_user';
+
+export async function getToken(): Promise {
+ if (Platform.OS === 'web') {
+ return localStorage.getItem(TOKEN_KEY);
+ }
+ return SecureStore.getItemAsync(TOKEN_KEY);
+}
+
+export async function setToken(token: string): Promise {
+ if (Platform.OS === 'web') {
+ localStorage.setItem(TOKEN_KEY, token);
+ return;
+ }
+ await SecureStore.setItemAsync(TOKEN_KEY, token);
+}
+
+export async function removeToken(): Promise {
+ if (Platform.OS === 'web') {
+ localStorage.removeItem(TOKEN_KEY);
+ return;
+ }
+ await SecureStore.deleteItemAsync(TOKEN_KEY);
+}
+
+export async function getUser(): Promise {
+ let raw: string | null;
+ if (Platform.OS === 'web') {
+ raw = localStorage.getItem(USER_KEY);
+ } else {
+ raw = await SecureStore.getItemAsync(USER_KEY);
+ }
+ if (!raw) return null;
+ try {
+ return JSON.parse(raw);
+ } catch {
+ return null;
+ }
+}
+
+export async function setUser(user: any): Promise {
+ const raw = JSON.stringify(user);
+ if (Platform.OS === 'web') {
+ localStorage.setItem(USER_KEY, raw);
+ return;
+ }
+ await SecureStore.setItemAsync(USER_KEY, raw);
+}
+
+export async function removeUser(): Promise {
+ if (Platform.OS === 'web') {
+ localStorage.removeItem(USER_KEY);
+ return;
+ }
+ await SecureStore.deleteItemAsync(USER_KEY);
+}
diff --git a/mobile/lib/useAuth.ts b/mobile/lib/useAuth.ts
new file mode 100644
index 0000000..02eceef
--- /dev/null
+++ b/mobile/lib/useAuth.ts
@@ -0,0 +1,44 @@
+import { useState, useEffect, useCallback } from 'react';
+import { getToken, setToken, removeToken, getUser, setUser, removeUser } from './auth';
+import * as api from './api';
+
+export function useAuth() {
+ const [token, setTokenState] = useState(null);
+ const [user, setUserState] = useState(null);
+ const [loading, setLoading] = useState(true);
+
+ useEffect(() => {
+ (async () => {
+ const t = await getToken();
+ const u = await getUser();
+ setTokenState(t);
+ setUserState(u);
+ setLoading(false);
+ })();
+ }, []);
+
+ const loginFn = useCallback(async (email: string, password: string) => {
+ const res = await api.login({ email, password });
+ await setToken(res.data.token);
+ await setUser(res.data.user);
+ setTokenState(res.data.token);
+ setUserState(res.data.user);
+ }, []);
+
+ const registerFn = useCallback(async (email: string, name: string, password: string) => {
+ const res = await api.register({ email, name, password });
+ await setToken(res.data.token);
+ await setUser(res.data.user);
+ setTokenState(res.data.token);
+ setUserState(res.data.user);
+ }, []);
+
+ const logout = useCallback(async () => {
+ await removeToken();
+ await removeUser();
+ setTokenState(null);
+ setUserState(null);
+ }, []);
+
+ return { token, user, loading, login: loginFn, register: registerFn, logout };
+}
diff --git a/mobile/package-lock.json b/mobile/package-lock.json
index 7199218..fc95645 100644
--- a/mobile/package-lock.json
+++ b/mobile/package-lock.json
@@ -1,13 +1,14 @@
{
- "name": "mobile",
+ "name": "task-team-mobile",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
- "name": "mobile",
+ "name": "task-team-mobile",
"version": "1.0.0",
"dependencies": {
+ "@expo/vector-icons": "^14.0.4",
"@react-navigation/native": "^7.2.2",
"expo": "~54.0.33",
"expo-constants": "~18.0.13",
@@ -17,12 +18,17 @@
"expo-router": "~6.0.23",
"expo-secure-store": "~15.0.8",
"expo-status-bar": "~3.0.9",
+ "nativewind": "^4.1.23",
"react": "19.1.0",
+ "react-dom": "19.1.0",
"react-native": "0.81.5",
+ "react-native-css-interop": "^0.2.3",
"react-native-gesture-handler": "^2.30.1",
"react-native-reanimated": "^4.3.0",
"react-native-safe-area-context": "~5.6.0",
- "react-native-screens": "~4.16.0"
+ "react-native-screens": "~4.16.0",
+ "react-native-web": "^0.21.0",
+ "tailwindcss": "^3.4.19"
},
"devDependencies": {
"@types/react": "~19.1.0",
@@ -43,6 +49,18 @@
}
}
},
+ "node_modules/@alloc/quick-lru": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
+ "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/@babel/code-frame": {
"version": "7.10.4",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz",
@@ -2240,6 +2258,17 @@
"integrity": "sha512-HHQigo3rQWKMDzYDLkubN5WQOYXJJE2eNqIQC2axC2iO3mHdwnIR7FgZVvHWtBwAdzBgAP0ECp8KqS8TiMKvgw==",
"license": "MIT"
},
+ "node_modules/@expo/vector-icons": {
+ "version": "14.1.0",
+ "resolved": "https://registry.npmjs.org/@expo/vector-icons/-/vector-icons-14.1.0.tgz",
+ "integrity": "sha512-7T09UE9h8QDTsUeMGymB4i+iqvtEeaO5VvUjryFB4tugDTG/bkzViWA74hm5pfjjDEhYMXWaX112mcvhccmIwQ==",
+ "license": "MIT",
+ "peerDependencies": {
+ "expo-font": "*",
+ "react": "*",
+ "react-native": "*"
+ }
+ },
"node_modules/@expo/ws-tunnel": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/@expo/ws-tunnel/-/ws-tunnel-1.0.6.tgz",
@@ -2717,6 +2746,41 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
+ "node_modules/@nodelib/fs.scandir": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+ "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.stat": "2.0.5",
+ "run-parallel": "^1.1.9"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.stat": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+ "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.walk": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+ "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.scandir": "2.1.5",
+ "fastq": "^1.6.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
"node_modules/@radix-ui/primitive": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz",
@@ -3756,6 +3820,12 @@
"node": ">=10"
}
},
+ "node_modules/array-timsort": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/array-timsort/-/array-timsort-1.0.3.tgz",
+ "integrity": "sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==",
+ "license": "MIT"
+ },
"node_modules/asap": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
@@ -4138,6 +4208,18 @@
"node": ">=0.6"
}
},
+ "node_modules/binary-extensions": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
+ "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/bplist-creator": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.1.0.tgz",
@@ -4321,6 +4403,15 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/camelcase-css": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
+ "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/caniuse-lite": {
"version": "1.0.30001781",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001781.tgz",
@@ -4355,6 +4446,42 @@
"node": ">=4"
}
},
+ "node_modules/chokidar": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
+ "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
+ "license": "MIT",
+ "dependencies": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/chokidar/node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/chownr": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz",
@@ -4544,6 +4671,19 @@
"node": ">= 10"
}
},
+ "node_modules/comment-json": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.6.2.tgz",
+ "integrity": "sha512-R2rze/hDX30uul4NZoIZ76ImSJLFxn/1/ZxtKC1L77y2X1k+yYu1joKbAtMA2Fg3hZrTOiw0I5mwVMo0cf250w==",
+ "license": "MIT",
+ "dependencies": {
+ "array-timsort": "^1.0.3",
+ "esprima": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/compressible": {
"version": "2.0.18",
"resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz",
@@ -4653,6 +4793,15 @@
"url": "https://opencollective.com/core-js"
}
},
+ "node_modules/cross-fetch": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.2.0.tgz",
+ "integrity": "sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==",
+ "license": "MIT",
+ "dependencies": {
+ "node-fetch": "^2.7.0"
+ }
+ },
"node_modules/cross-spawn": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
@@ -4667,6 +4816,27 @@
"node": ">= 8"
}
},
+ "node_modules/css-in-js-utils": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/css-in-js-utils/-/css-in-js-utils-3.1.0.tgz",
+ "integrity": "sha512-fJAcud6B3rRu+KHYk+Bwf+WFL2MDCJJ1XG9x137tJQ0xYxor7XziQtuGFbWNdqrvF4Tk26O3H73nfVqXt/fW1A==",
+ "license": "MIT",
+ "dependencies": {
+ "hyphenate-style-name": "^1.0.3"
+ }
+ },
+ "node_modules/cssesc": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
+ "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
+ "license": "MIT",
+ "bin": {
+ "cssesc": "bin/cssesc"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/csstype": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
@@ -4807,6 +4977,18 @@
"integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==",
"license": "MIT"
},
+ "node_modules/didyoumean": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
+ "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==",
+ "license": "Apache-2.0"
+ },
+ "node_modules/dlv": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
+ "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
+ "license": "MIT"
+ },
"node_modules/dotenv": {
"version": "16.4.7",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz",
@@ -5067,6 +5249,21 @@
"expo": "*"
}
},
+ "node_modules/expo-font": {
+ "version": "55.0.4",
+ "resolved": "https://registry.npmjs.org/expo-font/-/expo-font-55.0.4.tgz",
+ "integrity": "sha512-ZKeGTFffPygvY5dM/9ATM2p7QDkhsaHopH7wFAWgP2lKzqUMS9B/RxCvw5CaObr9Ro7x9YptyeRKX2HmgmMfrg==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "fontfaceobserver": "^2.1.0"
+ },
+ "peerDependencies": {
+ "expo": "*",
+ "react": "*",
+ "react-native": "*"
+ }
+ },
"node_modules/expo-linking": {
"version": "8.0.11",
"resolved": "https://registry.npmjs.org/expo-linking/-/expo-linking-8.0.11.tgz",
@@ -5928,12 +6125,49 @@
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"license": "MIT"
},
+ "node_modules/fast-glob": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
+ "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.2",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.8"
+ },
+ "engines": {
+ "node": ">=8.6.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
"license": "MIT"
},
+ "node_modules/fastq": {
+ "version": "1.20.1",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz",
+ "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==",
+ "license": "ISC",
+ "dependencies": {
+ "reusify": "^1.0.4"
+ }
+ },
"node_modules/fb-watchman": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz",
@@ -5943,6 +6177,62 @@
"bser": "2.1.1"
}
},
+ "node_modules/fbjs": {
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-3.0.5.tgz",
+ "integrity": "sha512-ztsSx77JBtkuMrEypfhgc3cI0+0h+svqeie7xHbh1k/IKdcydnvadp/mUaGgjAOXQmQSxsqgaRhS3q9fy+1kxg==",
+ "license": "MIT",
+ "dependencies": {
+ "cross-fetch": "^3.1.5",
+ "fbjs-css-vars": "^1.0.0",
+ "loose-envify": "^1.0.0",
+ "object-assign": "^4.1.0",
+ "promise": "^7.1.1",
+ "setimmediate": "^1.0.5",
+ "ua-parser-js": "^1.0.35"
+ }
+ },
+ "node_modules/fbjs-css-vars": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz",
+ "integrity": "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==",
+ "license": "MIT"
+ },
+ "node_modules/fbjs/node_modules/promise": {
+ "version": "7.3.1",
+ "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
+ "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
+ "license": "MIT",
+ "dependencies": {
+ "asap": "~2.0.3"
+ }
+ },
+ "node_modules/fbjs/node_modules/ua-parser-js": {
+ "version": "1.0.41",
+ "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.41.tgz",
+ "integrity": "sha512-LbBDqdIC5s8iROCUjMbW1f5dJQTEFB1+KO9ogbvlb3nm9n4YHa5p4KTvFPWvh2Hs8gZMBuiB1/8+pdfe/tDPug==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/ua-parser-js"
+ },
+ {
+ "type": "paypal",
+ "url": "https://paypal.me/faisalman"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/faisalman"
+ }
+ ],
+ "license": "MIT",
+ "bin": {
+ "ua-parser-js": "script/cli.js"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/fill-range": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
@@ -6192,6 +6482,18 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/glob-parent": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
"node_modules/glob/node_modules/balanced-match": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
@@ -6396,6 +6698,12 @@
"node": ">= 14"
}
},
+ "node_modules/hyphenate-style-name": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.1.0.tgz",
+ "integrity": "sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==",
+ "license": "BSD-3-Clause"
+ },
"node_modules/ieee754": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
@@ -6472,6 +6780,15 @@
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
"license": "ISC"
},
+ "node_modules/inline-style-prefixer": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/inline-style-prefixer/-/inline-style-prefixer-7.0.1.tgz",
+ "integrity": "sha512-lhYo5qNTQp3EvSSp3sRvXMbVQTLrvGV6DycRMJ5dm2BLMiJ30wpXKdDdgX+GmJZ5uQMucwRKHamXSst3Sj/Giw==",
+ "license": "MIT",
+ "dependencies": {
+ "css-in-js-utils": "^3.1.0"
+ }
+ },
"node_modules/invariant": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
@@ -6503,6 +6820,18 @@
"integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==",
"license": "MIT"
},
+ "node_modules/is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "license": "MIT",
+ "dependencies": {
+ "binary-extensions": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/is-callable": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
@@ -6545,6 +6874,15 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
@@ -6573,6 +6911,18 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "license": "MIT",
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/is-nan": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz",
@@ -7095,6 +7445,16 @@
"integrity": "sha512-dZ6Ra7u1G8c4Letq/B5EzAxj4tLFHL+cGtdpR+PVm4yzPDj+lCk+AbivWt1eOM+ikzkowtyV7qSqX6qr3t71Ww==",
"license": "MIT"
},
+ "node_modules/jiti": {
+ "version": "1.21.7",
+ "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz",
+ "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==",
+ "license": "MIT",
+ "peer": true,
+ "bin": {
+ "jiti": "bin/jiti.js"
+ }
+ },
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -7445,6 +7805,18 @@
"url": "https://opencollective.com/parcel"
}
},
+ "node_modules/lilconfig": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
+ "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antonk52"
+ }
+ },
"node_modules/lines-and-columns": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
@@ -7544,6 +7916,15 @@
"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
"license": "MIT"
},
+ "node_modules/merge2": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
"node_modules/metro": {
"version": "0.83.3",
"resolved": "https://registry.npmjs.org/metro/-/metro-0.83.3.tgz",
@@ -8044,6 +8425,23 @@
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
+ "node_modules/nativewind": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/nativewind/-/nativewind-4.2.3.tgz",
+ "integrity": "sha512-HglF1v6A8CqBFpXWs0d3yf4qQGurrreLuyE8FTRI/VDH8b0npZa2SDG5tviTkLiBg0s5j09mQALZOjxuocgMLA==",
+ "license": "MIT",
+ "dependencies": {
+ "comment-json": "^4.2.5",
+ "debug": "^4.3.7",
+ "react-native-css-interop": "0.2.3"
+ },
+ "engines": {
+ "node": ">=16"
+ },
+ "peerDependencies": {
+ "tailwindcss": ">3.3.0"
+ }
+ },
"node_modules/negotiator": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
@@ -8059,6 +8457,26 @@
"integrity": "sha512-SrQrok4CATudVzBS7coSz26QRSmlK9TzzoFbeKfcPBUFPjcQM9Rqvr/DlJkOrwI/0KcgvMub1n1g5Jt9EgRn4A==",
"license": "MIT"
},
+ "node_modules/node-fetch": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
+ "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
+ "license": "MIT",
+ "dependencies": {
+ "whatwg-url": "^5.0.0"
+ },
+ "engines": {
+ "node": "4.x || >=6.0.0"
+ },
+ "peerDependencies": {
+ "encoding": "^0.1.0"
+ },
+ "peerDependenciesMeta": {
+ "encoding": {
+ "optional": true
+ }
+ }
+ },
"node_modules/node-forge": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.4.0.tgz",
@@ -8131,6 +8549,15 @@
"node": ">=0.10.0"
}
},
+ "node_modules/object-hash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
+ "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/object-is": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz",
@@ -8420,6 +8847,15 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
+ "node_modules/pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/pirates": {
"version": "4.0.7",
"resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz",
@@ -8480,6 +8916,7 @@
}
],
"license": "MIT",
+ "peer": true,
"dependencies": {
"nanoid": "^3.3.7",
"picocolors": "^1.1.1",
@@ -8489,6 +8926,134 @@
"node": "^10 || ^12 || >=14"
}
},
+ "node_modules/postcss-import": {
+ "version": "15.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz",
+ "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==",
+ "license": "MIT",
+ "dependencies": {
+ "postcss-value-parser": "^4.0.0",
+ "read-cache": "^1.0.0",
+ "resolve": "^1.1.7"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.0.0"
+ }
+ },
+ "node_modules/postcss-js": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz",
+ "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "camelcase-css": "^2.0.1"
+ },
+ "engines": {
+ "node": "^12 || ^14 || >= 16"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.21"
+ }
+ },
+ "node_modules/postcss-load-config": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz",
+ "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "lilconfig": "^3.1.1"
+ },
+ "engines": {
+ "node": ">= 18"
+ },
+ "peerDependencies": {
+ "jiti": ">=1.21.0",
+ "postcss": ">=8.0.9",
+ "tsx": "^4.8.1",
+ "yaml": "^2.4.2"
+ },
+ "peerDependenciesMeta": {
+ "jiti": {
+ "optional": true
+ },
+ "postcss": {
+ "optional": true
+ },
+ "tsx": {
+ "optional": true
+ },
+ "yaml": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/postcss-nested": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz",
+ "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "postcss-selector-parser": "^6.1.1"
+ },
+ "engines": {
+ "node": ">=12.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.2.14"
+ }
+ },
+ "node_modules/postcss-selector-parser": {
+ "version": "6.1.2",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
+ "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
+ "license": "MIT",
+ "dependencies": {
+ "cssesc": "^3.0.0",
+ "util-deprecate": "^1.0.2"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/postcss-value-parser": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
+ "license": "MIT"
+ },
"node_modules/pretty-bytes": {
"version": "5.6.0",
"resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz",
@@ -8611,6 +9176,26 @@
"inherits": "~2.0.3"
}
},
+ "node_modules/queue-microtask": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
"node_modules/range-parser": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
@@ -8640,6 +9225,7 @@
"resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz",
"integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==",
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -8655,24 +9241,18 @@
}
},
"node_modules/react-dom": {
- "version": "19.2.4",
- "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz",
- "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==",
+ "version": "19.1.0",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz",
+ "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==",
"license": "MIT",
"peer": true,
"dependencies": {
- "scheduler": "^0.27.0"
+ "scheduler": "^0.26.0"
},
"peerDependencies": {
- "react": "^19.2.4"
+ "react": "^19.1.0"
}
},
- "node_modules/react-dom/node_modules/scheduler": {
- "version": "0.27.0",
- "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
- "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
- "license": "MIT"
- },
"node_modules/react-fast-compare": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz",
@@ -8702,6 +9282,7 @@
"resolved": "https://registry.npmjs.org/react-native/-/react-native-0.81.5.tgz",
"integrity": "sha512-1w+/oSjEXZjMqsIvmkCRsOc8UBYv163bTWKTI8+1mxztvQPhCRYGTvZ/PL1w16xXHneIj/SLGfxWg2GWN2uexw==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@jest/create-cache-key-function": "^29.7.0",
"@react-native/assets-registry": "0.81.5",
@@ -8754,6 +9335,277 @@
}
}
},
+ "node_modules/react-native-css-interop": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/react-native-css-interop/-/react-native-css-interop-0.2.3.tgz",
+ "integrity": "sha512-wc+JI7iUfdFBqnE18HhMTtD0q9vkhuMczToA87UdHGWwMyxdT5sCcNy+i4KInPCE855IY0Ic8kLQqecAIBWz7w==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.22.15",
+ "@babel/traverse": "^7.23.0",
+ "@babel/types": "^7.23.0",
+ "debug": "^4.3.7",
+ "lightningcss": "~1.27.0",
+ "semver": "^7.6.3"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "react": ">=18",
+ "react-native": "*",
+ "react-native-reanimated": ">=3.6.2",
+ "tailwindcss": "~3"
+ },
+ "peerDependenciesMeta": {
+ "react-native-safe-area-context": {
+ "optional": true
+ },
+ "react-native-svg": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-native-css-interop/node_modules/detect-libc": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
+ "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
+ "license": "Apache-2.0",
+ "bin": {
+ "detect-libc": "bin/detect-libc.js"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/react-native-css-interop/node_modules/lightningcss": {
+ "version": "1.27.0",
+ "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.27.0.tgz",
+ "integrity": "sha512-8f7aNmS1+etYSLHht0fQApPc2kNO8qGRutifN5rVIc6Xo6ABsEbqOr758UwI7ALVbTt4x1fllKt0PYgzD9S3yQ==",
+ "license": "MPL-2.0",
+ "dependencies": {
+ "detect-libc": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ },
+ "optionalDependencies": {
+ "lightningcss-darwin-arm64": "1.27.0",
+ "lightningcss-darwin-x64": "1.27.0",
+ "lightningcss-freebsd-x64": "1.27.0",
+ "lightningcss-linux-arm-gnueabihf": "1.27.0",
+ "lightningcss-linux-arm64-gnu": "1.27.0",
+ "lightningcss-linux-arm64-musl": "1.27.0",
+ "lightningcss-linux-x64-gnu": "1.27.0",
+ "lightningcss-linux-x64-musl": "1.27.0",
+ "lightningcss-win32-arm64-msvc": "1.27.0",
+ "lightningcss-win32-x64-msvc": "1.27.0"
+ }
+ },
+ "node_modules/react-native-css-interop/node_modules/lightningcss-darwin-arm64": {
+ "version": "1.27.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.27.0.tgz",
+ "integrity": "sha512-Gl/lqIXY+d+ySmMbgDf0pgaWSqrWYxVHoc88q+Vhf2YNzZ8DwoRzGt5NZDVqqIW5ScpSnmmjcgXP87Dn2ylSSQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/react-native-css-interop/node_modules/lightningcss-darwin-x64": {
+ "version": "1.27.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.27.0.tgz",
+ "integrity": "sha512-0+mZa54IlcNAoQS9E0+niovhyjjQWEMrwW0p2sSdLRhLDc8LMQ/b67z7+B5q4VmjYCMSfnFi3djAAQFIDuj/Tg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/react-native-css-interop/node_modules/lightningcss-freebsd-x64": {
+ "version": "1.27.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.27.0.tgz",
+ "integrity": "sha512-n1sEf85fePoU2aDN2PzYjoI8gbBqnmLGEhKq7q0DKLj0UTVmOTwDC7PtLcy/zFxzASTSBlVQYJUhwIStQMIpRA==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/react-native-css-interop/node_modules/lightningcss-linux-arm-gnueabihf": {
+ "version": "1.27.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.27.0.tgz",
+ "integrity": "sha512-MUMRmtdRkOkd5z3h986HOuNBD1c2lq2BSQA1Jg88d9I7bmPGx08bwGcnB75dvr17CwxjxD6XPi3Qh8ArmKFqCA==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/react-native-css-interop/node_modules/lightningcss-linux-arm64-gnu": {
+ "version": "1.27.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.27.0.tgz",
+ "integrity": "sha512-cPsxo1QEWq2sfKkSq2Bq5feQDHdUEwgtA9KaB27J5AX22+l4l0ptgjMZZtYtUnteBofjee+0oW1wQ1guv04a7A==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/react-native-css-interop/node_modules/lightningcss-linux-arm64-musl": {
+ "version": "1.27.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.27.0.tgz",
+ "integrity": "sha512-rCGBm2ax7kQ9pBSeITfCW9XSVF69VX+fm5DIpvDZQl4NnQoMQyRwhZQm9pd59m8leZ1IesRqWk2v/DntMo26lg==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/react-native-css-interop/node_modules/lightningcss-linux-x64-gnu": {
+ "version": "1.27.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.27.0.tgz",
+ "integrity": "sha512-Dk/jovSI7qqhJDiUibvaikNKI2x6kWPN79AQiD/E/KeQWMjdGe9kw51RAgoWFDi0coP4jinaH14Nrt/J8z3U4A==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/react-native-css-interop/node_modules/lightningcss-linux-x64-musl": {
+ "version": "1.27.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.27.0.tgz",
+ "integrity": "sha512-QKjTxXm8A9s6v9Tg3Fk0gscCQA1t/HMoF7Woy1u68wCk5kS4fR+q3vXa1p3++REW784cRAtkYKrPy6JKibrEZA==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/react-native-css-interop/node_modules/lightningcss-win32-arm64-msvc": {
+ "version": "1.27.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.27.0.tgz",
+ "integrity": "sha512-/wXegPS1hnhkeG4OXQKEMQeJd48RDC3qdh+OA8pCuOPCyvnm/yEayrJdJVqzBsqpy1aJklRCVxscpFur80o6iQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/react-native-css-interop/node_modules/lightningcss-win32-x64-msvc": {
+ "version": "1.27.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.27.0.tgz",
+ "integrity": "sha512-/OJLj94Zm/waZShL8nB5jsNj3CfNATLCTyFxZyouilfTmSoLDX7VlVAmhPHoZWVFp4vdmoiEbPEYC8HID3m6yw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
"node_modules/react-native-gesture-handler": {
"version": "2.30.1",
"resolved": "https://registry.npmjs.org/react-native-gesture-handler/-/react-native-gesture-handler-2.30.1.tgz",
@@ -8823,6 +9675,39 @@
"react-native": "*"
}
},
+ "node_modules/react-native-web": {
+ "version": "0.21.2",
+ "resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.21.2.tgz",
+ "integrity": "sha512-SO2t9/17zM4iEnFvlu2DA9jqNbzNhoUP+AItkoCOyFmDMOhUnBBznBDCYN92fGdfAkfQlWzPoez6+zLxFNsZEg==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@babel/runtime": "^7.18.6",
+ "@react-native/normalize-colors": "^0.74.1",
+ "fbjs": "^3.0.4",
+ "inline-style-prefixer": "^7.0.1",
+ "memoize-one": "^6.0.0",
+ "nullthrows": "^1.1.1",
+ "postcss-value-parser": "^4.2.0",
+ "styleq": "^0.1.3"
+ },
+ "peerDependencies": {
+ "react": "^18.0.0 || ^19.0.0",
+ "react-dom": "^18.0.0 || ^19.0.0"
+ }
+ },
+ "node_modules/react-native-web/node_modules/@react-native/normalize-colors": {
+ "version": "0.74.89",
+ "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.74.89.tgz",
+ "integrity": "sha512-qoMMXddVKVhZ8PA1AbUCk83trpd6N+1nF2A6k1i6LsQObyS92fELuk8kU/lQs6M7BsMHwqyLCpQJ1uFgNvIQXg==",
+ "license": "MIT"
+ },
+ "node_modules/react-native-web/node_modules/memoize-one": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz",
+ "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==",
+ "license": "MIT"
+ },
"node_modules/react-native-worklets": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/react-native-worklets/-/react-native-worklets-0.8.1.tgz",
@@ -9012,6 +9897,27 @@
}
}
},
+ "node_modules/read-cache": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
+ "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
+ "license": "MIT",
+ "dependencies": {
+ "pify": "^2.3.0"
+ }
+ },
+ "node_modules/readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "license": "MIT",
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
"node_modules/regenerate": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
@@ -9168,6 +10074,16 @@
"node": ">=4"
}
},
+ "node_modules/reusify": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
+ "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
+ "license": "MIT",
+ "engines": {
+ "iojs": ">=1.0.0",
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/rimraf": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
@@ -9227,6 +10143,29 @@
"node": "*"
}
},
+ "node_modules/run-parallel": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+ "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "queue-microtask": "^1.2.2"
+ }
+ },
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
@@ -9416,6 +10355,12 @@
"node": ">= 0.4"
}
},
+ "node_modules/setimmediate": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
+ "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==",
+ "license": "MIT"
+ },
"node_modules/setprototypeof": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
@@ -9679,6 +10624,12 @@
"integrity": "sha512-0MP/Cxx5SzeeZ10p/bZI0S6MpgD+yxAhi1BOQ34jgnMXsCq3j1t6tQnZu+KdlL7dvJTLT3g9xN8tl10TqgFMcg==",
"license": "MIT"
},
+ "node_modules/styleq": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/styleq/-/styleq-0.1.3.tgz",
+ "integrity": "sha512-3ZUifmCDCQanjeej1f6kyl/BeP/Vae5EYkQ9iJfUm/QwZvlgnZzyflqAsAWYURdtea8Vkvswu2GrC57h3qffcA==",
+ "license": "MIT"
+ },
"node_modules/sucrase": {
"version": "3.35.1",
"resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz",
@@ -9768,6 +10719,44 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/tailwindcss": {
+ "version": "3.4.19",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz",
+ "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@alloc/quick-lru": "^5.2.0",
+ "arg": "^5.0.2",
+ "chokidar": "^3.6.0",
+ "didyoumean": "^1.2.2",
+ "dlv": "^1.1.3",
+ "fast-glob": "^3.3.2",
+ "glob-parent": "^6.0.2",
+ "is-glob": "^4.0.3",
+ "jiti": "^1.21.7",
+ "lilconfig": "^3.1.3",
+ "micromatch": "^4.0.8",
+ "normalize-path": "^3.0.0",
+ "object-hash": "^3.0.0",
+ "picocolors": "^1.1.1",
+ "postcss": "^8.4.47",
+ "postcss-import": "^15.1.0",
+ "postcss-js": "^4.0.1",
+ "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0",
+ "postcss-nested": "^6.2.0",
+ "postcss-selector-parser": "^6.1.2",
+ "resolve": "^1.22.8",
+ "sucrase": "^3.35.0"
+ },
+ "bin": {
+ "tailwind": "lib/cli.js",
+ "tailwindcss": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
"node_modules/tar": {
"version": "7.5.13",
"resolved": "https://registry.npmjs.org/tar/-/tar-7.5.13.tgz",
@@ -9990,6 +10979,12 @@
"node": ">=0.6"
}
},
+ "node_modules/tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
+ "license": "MIT"
+ },
"node_modules/ts-interface-checker": {
"version": "0.1.13",
"resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
@@ -10228,6 +11223,12 @@
"which-typed-array": "^1.1.2"
}
},
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+ "license": "MIT"
+ },
"node_modules/utils-merge": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
@@ -10499,6 +11500,16 @@
"integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==",
"license": "MIT"
},
+ "node_modules/whatwg-url": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+ "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+ "license": "MIT",
+ "dependencies": {
+ "tr46": "~0.0.3",
+ "webidl-conversions": "^3.0.0"
+ }
+ },
"node_modules/whatwg-url-without-unicode": {
"version": "8.0.0-3",
"resolved": "https://registry.npmjs.org/whatwg-url-without-unicode/-/whatwg-url-without-unicode-8.0.0-3.tgz",
@@ -10513,6 +11524,12 @@
"node": ">=10"
}
},
+ "node_modules/whatwg-url/node_modules/webidl-conversions": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
+ "license": "BSD-2-Clause"
+ },
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
diff --git a/mobile/package.json b/mobile/package.json
index 1e67c6a..c638d6d 100644
--- a/mobile/package.json
+++ b/mobile/package.json
@@ -1,14 +1,17 @@
{
- "name": "mobile",
+ "name": "task-team-mobile",
"version": "1.0.0",
"main": "index.ts",
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
- "web": "expo start --web"
+ "web": "expo start --web",
+ "export:web": "expo export --platform web",
+ "lint": "expo lint"
},
"dependencies": {
+ "@expo/vector-icons": "^14.0.4",
"@react-navigation/native": "^7.2.2",
"expo": "~54.0.33",
"expo-constants": "~18.0.13",
@@ -18,12 +21,17 @@
"expo-router": "~6.0.23",
"expo-secure-store": "~15.0.8",
"expo-status-bar": "~3.0.9",
+ "nativewind": "^4.1.23",
"react": "19.1.0",
+ "react-dom": "19.1.0",
"react-native": "0.81.5",
+ "react-native-css-interop": "^0.2.3",
"react-native-gesture-handler": "^2.30.1",
"react-native-reanimated": "^4.3.0",
"react-native-safe-area-context": "~5.6.0",
- "react-native-screens": "~4.16.0"
+ "react-native-screens": "~4.16.0",
+ "react-native-web": "^0.21.0",
+ "tailwindcss": "^3.4.19"
},
"devDependencies": {
"@types/react": "~19.1.0",
diff --git a/mobile/tsconfig.json b/mobile/tsconfig.json
index b9567f6..afc4d25 100644
--- a/mobile/tsconfig.json
+++ b/mobile/tsconfig.json
@@ -1,6 +1,11 @@
{
"extends": "expo/tsconfig.base",
"compilerOptions": {
- "strict": true
- }
+ "strict": true,
+ "baseUrl": ".",
+ "paths": {
+ "@/*": ["./*"]
+ }
+ },
+ "include": ["**/*.ts", "**/*.tsx", ".expo/types/**/*.ts", "expo-env.d.ts"]
}