From 9cc6d17607c3e63e4f677a3b6ec62281beede6a7 Mon Sep 17 00:00:00 2001 From: Linus Waldowsky Date: Sat, 3 Jan 2026 10:47:12 +0100 Subject: [PATCH] implement frontend skeleton with tab navigation and service layer - Add tab-based navigation (Chat, Calendar) using Expo-Router - Create auth screens (login, register) as skeletons - Add dynamic routes for event detail and note editing - Implement service layer (ApiClient, AuthService, EventService, ChatService) - Add Zustand stores (AuthStore, EventsStore) for state management - Create EventCard and EventConfirmDialog components - Update CLAUDE.md with new frontend architecture documentation - Add Zustand and FlashList to technology stack --- CLAUDE.md | 49 +++++++++++++++--- apps/client/package.json | 3 +- apps/client/src/app/(tabs)/_layout.tsx | 29 +++++++++++ .../app/{Calender.tsx => (tabs)/calendar.tsx} | 8 +-- .../src/app/{Chat.tsx => (tabs)/chat.tsx} | 6 +-- apps/client/src/app/Hello_World.tsx | 49 ------------------ apps/client/src/app/_layout.tsx | 10 +++- apps/client/src/app/event/[id].tsx | 44 ++++++++++++++++ apps/client/src/app/index.tsx | 9 +--- apps/client/src/app/login.tsx | 34 +++++++++++++ apps/client/src/app/note/[id].tsx | 34 +++++++++++++ apps/client/src/app/register.tsx | 45 ++++++++++++++++ apps/client/src/components/EventCard.tsx | 24 +++++++++ .../src/components/EventConfirmDialog.tsx | 36 +++++++++++++ apps/client/src/services/ApiClient.ts | 51 +++++++++++++++++++ apps/client/src/services/AuthService.ts | 19 +++++++ apps/client/src/services/ChatService.ts | 39 ++++++++++++++ apps/client/src/services/EventService.ts | 27 ++++++++++ apps/client/src/services/index.ts | 4 ++ apps/client/src/stores/AuthStore.ts | 26 ++++++++++ apps/client/src/stores/EventsStore.ts | 26 ++++++++++ apps/client/src/stores/index.ts | 2 + apps/client/tsconfig.json | 6 ++- package-lock.json | 32 +++++++++++- 24 files changed, 537 insertions(+), 75 deletions(-) create mode 100644 apps/client/src/app/(tabs)/_layout.tsx rename apps/client/src/app/{Calender.tsx => (tabs)/calendar.tsx} (97%) rename apps/client/src/app/{Chat.tsx => (tabs)/chat.tsx} (97%) delete mode 100644 apps/client/src/app/Hello_World.tsx create mode 100644 apps/client/src/app/event/[id].tsx create mode 100644 apps/client/src/app/login.tsx create mode 100644 apps/client/src/app/note/[id].tsx create mode 100644 apps/client/src/app/register.tsx create mode 100644 apps/client/src/components/EventCard.tsx create mode 100644 apps/client/src/components/EventConfirmDialog.tsx create mode 100644 apps/client/src/services/ApiClient.ts create mode 100644 apps/client/src/services/AuthService.ts create mode 100644 apps/client/src/services/ChatService.ts create mode 100644 apps/client/src/services/EventService.ts create mode 100644 apps/client/src/services/index.ts create mode 100644 apps/client/src/stores/AuthStore.ts create mode 100644 apps/client/src/stores/EventsStore.ts create mode 100644 apps/client/src/stores/index.ts diff --git a/CLAUDE.md b/CLAUDE.md index 78c34df..aa779b7 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -39,6 +39,8 @@ npm run start -w @caldav/server # Run compiled server (port 3000) | | Expo | Development platform | | | Expo-Router | File-based routing | | | NativeWind | Tailwind CSS for React Native | +| | Zustand | State management | +| | FlashList | High-performance lists | | Backend | Express.js | Web framework | | | MongoDB | Database | | | Mongoose | ODM | @@ -57,13 +59,39 @@ packages/shared - @caldav/shared - Shared TypeScript types and models ### Frontend Architecture (apps/client) -**Screens** (`src/app/`): Login, Register, Calendar, Chat, Event Detail, Notes - file-based routing via Expo-Router +``` +src/ +├── app/ # Expo-Router file-based routing +│ ├── _layout.tsx # Root Stack layout +│ ├── index.tsx # Entry redirect +│ ├── login.tsx # Login screen +│ ├── register.tsx # Registration screen +│ ├── (tabs)/ # Tab navigation group +│ │ ├── _layout.tsx # Tab bar configuration +│ │ ├── chat.tsx # Chat screen (AI conversation) +│ │ └── calendar.tsx # Calendar overview +│ ├── event/ +│ │ └── [id].tsx # Event detail screen (dynamic route) +│ └── note/ +│ └── [id].tsx # Note editor for event (dynamic route) +├── components/ +│ ├── BaseBackground.tsx # Common screen wrapper +│ ├── Header.tsx # Header component +│ ├── EventCard.tsx # Event card for calendar display +│ └── EventConfirmDialog.tsx # AI-proposed event confirmation modal +├── services/ +│ ├── index.ts # Re-exports all services +│ ├── ApiClient.ts # HTTP client (get, post, put, delete) +│ ├── AuthService.ts # login(), register(), logout(), refresh() +│ ├── EventService.ts # getAll(), getById(), getByDateRange(), create(), update(), delete() +│ └── ChatService.ts # sendMessage(), confirmEvent(), rejectEvent(), getConversations(), getConversation() +└── stores/ # Zustand state management + ├── index.ts # Re-exports all stores + ├── AuthStore.ts # user, token, isAuthenticated, login(), logout(), setToken() + └── EventsStore.ts # events[], setEvents(), addEvent(), updateEvent(), deleteEvent() +``` -**Services**: API Client for HTTP requests, plus AuthService, EventService, ChatService for domain logic - -**Components**: Reusable UI (EventCard, ChatBubble, EventConfirmDialog, MonthSelector) - -**Stores**: AuthStore (user + token), EventsStore (calendar events) +**Routing:** Tab-based navigation with Chat and Calendar as main screens. Auth screens (login, register) outside tabs. Dynamic routes for event detail and note editing. ### Backend Architecture (apps/server) @@ -176,7 +204,14 @@ The repository pattern allows swapping databases: **Shared:** Types and DTOs defined and exported. -**Frontend:** Calendar screen partially implemented, Chat screen exists but not connected to backend. +**Frontend:** Skeleton complete with file-based routing structure: +- Tab navigation (Chat, Calendar) implemented with basic UI +- Calendar screen has month navigation and grid display (partially functional) +- Chat screen has message list UI with FlashList (mock data only) +- Auth screens (Login, Register), Event Detail, and Note screens exist as skeletons +- Services (ApiClient, AuthService, EventService, ChatService) defined with `throw new Error('Not implemented')` +- Zustand stores (AuthStore, EventsStore) defined with `throw new Error('Not implemented')` +- Components (EventCard, EventConfirmDialog) exist as skeletons ## Documentation diff --git a/apps/client/package.json b/apps/client/package.json index ec468c6..b87bb6e 100644 --- a/apps/client/package.json +++ b/apps/client/package.json @@ -38,7 +38,8 @@ "react-native-safe-area-context": "5.6.0", "react-native-screens": "~4.16.0", "react-native-web": "~0.21.0", - "react-native-worklets": "0.5.1" + "react-native-worklets": "0.5.1", + "zustand": "^5.0.9" }, "devDependencies": { "@types/react": "~19.1.0", diff --git a/apps/client/src/app/(tabs)/_layout.tsx b/apps/client/src/app/(tabs)/_layout.tsx new file mode 100644 index 0000000..378e1ac --- /dev/null +++ b/apps/client/src/app/(tabs)/_layout.tsx @@ -0,0 +1,29 @@ +import { Ionicons } from "@expo/vector-icons"; +import { Tabs } from "expo-router"; +import theme from "../../Themes"; + +export default function TabLayout() { + return ( + + , + }} + /> + , + }} + /> + + ); +} diff --git a/apps/client/src/app/Calender.tsx b/apps/client/src/app/(tabs)/calendar.tsx similarity index 97% rename from apps/client/src/app/Calender.tsx rename to apps/client/src/app/(tabs)/calendar.tsx index 5fe108a..7a7603d 100644 --- a/apps/client/src/app/Calender.tsx +++ b/apps/client/src/app/(tabs)/calendar.tsx @@ -1,9 +1,9 @@ import { Animated, Modal, Pressable, Text, View } from "react-native"; -import { DAYS, MONTHS, Month } from "../Constants"; -import Header from "../components/Header"; +import { DAYS, MONTHS, Month } from "../../Constants"; +import Header from "../../components/Header"; import React, { useEffect, useMemo, useRef, useState } from "react"; -import currentTheme from "../Themes"; -import BaseBackground from "../components/BaseBackground"; +import currentTheme from "../../Themes"; +import BaseBackground from "../../components/BaseBackground"; import { FlashList } from "@shopify/flash-list"; // TODO: month selection dropdown menu diff --git a/apps/client/src/app/Chat.tsx b/apps/client/src/app/(tabs)/chat.tsx similarity index 97% rename from apps/client/src/app/Chat.tsx rename to apps/client/src/app/(tabs)/chat.tsx index ffcf803..ff4684c 100644 --- a/apps/client/src/app/Chat.tsx +++ b/apps/client/src/app/(tabs)/chat.tsx @@ -1,8 +1,8 @@ import { View, Text, TextInput } from "react-native"; -import currentTheme from "../Themes"; +import currentTheme from "../../Themes"; import { useState } from "react"; -import Header from "../components/Header"; -import BaseBackground from "../components/BaseBackground"; +import Header from "../../components/Header"; +import BaseBackground from "../../components/BaseBackground"; import { FlashList } from "@shopify/flash-list"; // TODO: better shadows for everything diff --git a/apps/client/src/app/Hello_World.tsx b/apps/client/src/app/Hello_World.tsx deleted file mode 100644 index f9e177d..0000000 --- a/apps/client/src/app/Hello_World.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import React, { useState } from 'react'; -import { Button, Text, View } from 'react-native'; - -// const styles = StyleSheet.create({ -// container: { -// alignItems: 'center', -// }, -// text: { -// fontSize: 40 -// } -// }) - -type HelloWorldProps = { - text: string; - aNumber: number; -} - -const HelloWorld = (props: HelloWorldProps) => { - return ( - - {props.text} : {props.aNumber} - - ) -} - -const Counter = () => { - const [count, setCount] = useState(0); - - return ( - -