Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,4 @@ testem.log
# System files
.DS_Store
Thumbs.db
CLAUDE.md
5 changes: 5 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"recommendations": [
"Webnative.webnative"
]
}
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"typescript.preferences.autoImportFileExcludePatterns": ["@ionic/angular/common", "@ionic/angular/standalone"]
}
42 changes: 20 additions & 22 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,35 +1,33 @@
# chat_app
# chat_app_v2

Angular 10 / Ionic 5 frontend for the Chatli messaging platform.

## Stack
- TypeScript, Angular 10, Ionic 5
- Capacitor for native mobile builds
- JWT-based auth (jwt-decode)
- WebSocket for real-time messaging
Angular 20 / Ionic 8 standalone chat client for the Chatli messaging backend.

## Build & run
```bash
eval "$(mise activate bash)"
npm install
npm start # Dev server
npm run build -- --prod # Production build
docker build -t fra/chatapp . && docker run -p 8100:8100 fra/chatapp
npm start # Dev server
npm run build # Production build
npm run lint # ESLint
```

## Test
```bash
npm test # Karma + Jasmine
npm run e2e # Protractor
npm run lint # TSLint
```
## Architecture
- Fully standalone components (no NgModules)
- Bootstrap: `bootstrapApplication()` with `provideIonicAngular()`
- Builder: `@angular-devkit/build-angular:application` with `browser` key
- Ionic imports: individual components from `@ionic/angular/standalone`
- Ionicons: `addIcons()` in component constructors
- State: Angular signals (`signal`, `computed`)
- HTTP: `withInterceptors([authInterceptor, errorInterceptor])`

## Backend connection
- REST API: http://localhost:8090/v1 (public), http://localhost:8090/client (auth required)
- REST API: http://localhost:8090/v1 (public), http://localhost:8090/client (auth)
- WebSocket: ws://localhost:8090/client/device/:deviceid/user/:userid/ws

## Structure
- `src/app/pages/` — page components (login, signup, chat, main)
- `src/app/services/` — auth, chat, message, storage services
- `src/app/models/` — data models (user, chat, message, participant)
- `src/app/helpers/` — HTTP interceptors (auth token injection, error handling)
- `src/app/pages/` — page components (login, signup, chats, contacts, messages, tabs)
- `src/app/services/` — auth, chat, message, user services
- `src/app/models/` — data models
- `src/app/components/` — reusable components (avatar)
- `src/app/guards/` — route guards
- `src/app/interceptors/` — auth + error interceptors
10 changes: 4 additions & 6 deletions src/app/pages/messages/messages.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,9 +179,8 @@ export class MessagesPage implements OnInit, OnDestroy {

this.chatService.getChat({ id: chatId } as Chat).subscribe((chat) => {
this.currentChat = chat;
const others = chat.participants ?? [];
this.title = others.length === 1 ? (others[0].username ?? chat.name ?? '') : (chat.name ?? '');
this.participants = [...others];
this.title = chat.name ?? '';
this.participants = [...(chat.participants ?? [])];
const currentUser = this.auth.currentUserValue;
if (currentUser) this.participants.push(currentUser);

Expand Down Expand Up @@ -258,9 +257,8 @@ export class MessagesPage implements OnInit, OnDestroy {
const { data } = await modal.onDidDismiss();
if (data) {
this.currentChat = data;
const updatedOthers = data.participants ?? [];
this.title = updatedOthers.length === 1 ? (updatedOthers[0].username ?? data.name ?? '') : (data.name ?? '');
this.participants = [...updatedOthers];
this.title = data.name ?? '';
this.participants = [...(data.participants ?? [])];
const currentUser = this.auth.currentUserValue;
if (currentUser) this.participants.push(currentUser);
}
Expand Down
Loading