chore: reorganize docs folder + add CLAUDE.md
- Kelompokkan docs/ ke subfolder: architecture/, testing/, notes/, ai/, tasks/ - Pindahkan tasks/ (root) ke docs/tasks/ - Tambah docs/README.md sebagai index navigasi - Tambah CLAUDE.md (project instructions) - Hapus .qwen/settings.json Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,22 +0,0 @@
|
||||
{
|
||||
"security": {
|
||||
"auth": {
|
||||
"selectedType": "openai"
|
||||
}
|
||||
},
|
||||
"env": {
|
||||
"OPENAI_BASE_URL": "https://claude-local.wibudev.com/v1",
|
||||
"OPENAI_API_KEY": "sk-T8mDcFAe83WWOQsHGx0JxvTmgBVdTQ2uFKzIRjZpwrh0H4Bg",
|
||||
"OPENAI_MODEL": "claude-sonnet-4-6"
|
||||
},
|
||||
"projectContext": {
|
||||
"enabled": false
|
||||
},
|
||||
"agent": {
|
||||
"enabled": false
|
||||
},
|
||||
"permissions": {
|
||||
"allow": []
|
||||
},
|
||||
"$version": 3
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(git add *)"
|
||||
]
|
||||
}
|
||||
}
|
||||
273
CLAUDE.md
Normal file
273
CLAUDE.md
Normal file
@@ -0,0 +1,273 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
---
|
||||
|
||||
## Project
|
||||
|
||||
**HIPMI Badung Connect** — Cross-platform mobile app (iOS, Android, Web) for HIPMI (Himpunan Pengusaha Muda Indonesia) chapter Badung members.
|
||||
|
||||
- Framework: Expo v54 + React Native v0.81.5, TypeScript strict
|
||||
- Routing: Expo Router v6 (file-based)
|
||||
- Package manager: Bun
|
||||
|
||||
---
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
bun install # install dependencies
|
||||
bunx expo start # dev server
|
||||
bunx expo start --ios # iOS simulator
|
||||
bunx expo start --android # Android emulator
|
||||
bunx expo start -c # clear cache
|
||||
bun run lint # expo lint
|
||||
|
||||
# Build (EAS)
|
||||
eas build --profile production
|
||||
eas build --profile preview
|
||||
eas build --profile development
|
||||
|
||||
# Troubleshooting
|
||||
rm -rf node_modules && bun install
|
||||
bunx expo start --clear
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Architecture
|
||||
|
||||
### Route → Screen separation (strict)
|
||||
|
||||
`app/` contains **route files only** (max 5 lines). All business logic lives in `screens/`.
|
||||
|
||||
```typescript
|
||||
// app/(application)/admin/feature/screen-name.tsx
|
||||
import { Admin_ScreenXXX } from "@/screens/Admin/Feature/ScreenXXX";
|
||||
export default function AdminScreenXXX() { return <Admin_ScreenXXX />; }
|
||||
```
|
||||
|
||||
```typescript
|
||||
// screens/Admin/Feature/ScreenXXX.tsx — ALL logic here
|
||||
export function Admin_ScreenXXX() {
|
||||
// hooks, state, handlers, render
|
||||
return <OS_Wrapper ... />;
|
||||
}
|
||||
```
|
||||
|
||||
### Naming conventions
|
||||
|
||||
| Item | Convention | Example |
|
||||
|---|---|---|
|
||||
| Admin screen | `Admin_ScreenXXX` | `Admin_ScreenDonationList` |
|
||||
| User screen | PascalCase | `ScreenDonationDetail` |
|
||||
| Admin card | `Admin_BoxXXX` | `Admin_BoxDonation` |
|
||||
| Path alias | `@/*` | `@/components/...` |
|
||||
|
||||
---
|
||||
|
||||
## Key Components
|
||||
|
||||
### OS_Wrapper — always use as root wrapper
|
||||
|
||||
Automatically selects iOS/Android layout. Two modes:
|
||||
|
||||
```typescript
|
||||
// List screen
|
||||
<OS_Wrapper
|
||||
listData={pagination.listData}
|
||||
renderItem={renderItem}
|
||||
headerComponent={headerComponent}
|
||||
ListEmptyComponent={ListEmptyComponent}
|
||||
ListFooterComponent={ListFooterComponent}
|
||||
onEndReached={pagination.loadMore}
|
||||
refreshControl={<RefreshControl refreshing={pagination.refreshing} onRefresh={pagination.onRefresh} />}
|
||||
/>
|
||||
|
||||
// Form screen (with TextInput / TextArea)
|
||||
<OS_Wrapper enableKeyboardHandling contentPaddingBottom={250}>
|
||||
<FormContent />
|
||||
</OS_Wrapper>
|
||||
```
|
||||
|
||||
- `contentPaddingBottom={100}` — default for list screens
|
||||
- `contentPaddingBottom={250}` — **only** for screens with TextInput/TextArea
|
||||
- `enableKeyboardHandling` — Android keyboard auto-scroll (ignored on iOS)
|
||||
|
||||
### AdminBasicBox + GridSpan_4_8
|
||||
|
||||
```typescript
|
||||
<AdminBasicBox onPress={() => router.push(`/path/${item.id}`)} style={{ marginHorizontal: 10, marginVertical: 5 }}>
|
||||
<StackCustom gap={0}>
|
||||
<GridSpan_4_8 label="Nama" value={<TextCustom>{item.name}</TextCustom>} />
|
||||
</StackCustom>
|
||||
</AdminBasicBox>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Pagination Pattern
|
||||
|
||||
```typescript
|
||||
import { usePagination } from "@/hooks/use-pagination";
|
||||
import { createPaginationComponents } from "@/helpers/paginationHelpers";
|
||||
import { PAGINATION_DEFAULT_TAKE } from "@/constants/constans-value";
|
||||
|
||||
const pagination = usePagination({
|
||||
fetchFunction: async (page, searchQuery) => {
|
||||
const response = await apiXXX({ page: String(page) });
|
||||
if (response.success) return { data: response.data };
|
||||
return { data: [] };
|
||||
},
|
||||
pageSize: PAGINATION_DEFAULT_TAKE, // 10
|
||||
searchQuery: search,
|
||||
dependencies: [dependency],
|
||||
});
|
||||
|
||||
const { ListEmptyComponent, ListFooterComponent } = createPaginationComponents({
|
||||
loading: pagination.loading,
|
||||
refreshing: pagination.refreshing,
|
||||
listData: pagination.listData,
|
||||
emptyMessage: "Belum ada data",
|
||||
skeletonCount: PAGINATION_DEFAULT_TAKE,
|
||||
});
|
||||
```
|
||||
|
||||
`usePagination` returns: `listData`, `loading`, `refreshing`, `hasMore`, `page`, `onRefresh`, `loadMore`, `reset`, `setListData`, `isInitialLoad`
|
||||
|
||||
---
|
||||
|
||||
## API Service Pattern
|
||||
|
||||
Always use `apiConfig` (not `axios` directly) — auth token injected automatically via request interceptor from `AsyncStorage.getItem("authToken")`.
|
||||
|
||||
```typescript
|
||||
// service/api-admin/api-xxx.ts
|
||||
export async function apiXXX({ page = "1" }: { page?: string }) {
|
||||
try {
|
||||
const response = await apiConfig.get(`/mobile/admin/xxx?page=${page}`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- All list endpoints require `page` param (default `"1"` as string)
|
||||
- Response shape: `{ success: boolean, data: T[], message?: string }`
|
||||
- Admin APIs: `service/api-admin/`
|
||||
- Client APIs: `service/api-client/`
|
||||
|
||||
---
|
||||
|
||||
## Authentication
|
||||
|
||||
```typescript
|
||||
// context/AuthContext.tsx — access via useAuth()
|
||||
const { user, token, isAdmin, isUserActive, loginWithNomor, validateOtp, logout } = useAuth();
|
||||
|
||||
// Role check
|
||||
const isAdmin = user?.masterUserRoleId !== "1"; // "1" = regular user
|
||||
|
||||
// Post-login routing
|
||||
// active user → /(application)/(user)/home
|
||||
// inactive user → /(application)/(user)/waiting-room
|
||||
```
|
||||
|
||||
AsyncStorage keys: `"authToken"`, `"userData"`
|
||||
|
||||
---
|
||||
|
||||
## File Upload
|
||||
|
||||
```typescript
|
||||
import { uploadFileService, deleteFileService } from "@/service/upload-service";
|
||||
import { API_IMAGE } from "@/constants/api-storage";
|
||||
|
||||
const result = await uploadFileService({ dirId: "folder-name", imageUri: localUri });
|
||||
// result.data.id → save this ID to backend
|
||||
|
||||
await deleteFileService({ id: fileId });
|
||||
|
||||
const imageUrl = API_IMAGE.GET({ fileId: "xxx", size: 200 }); // wibu-storage CDN
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Constants (`constants/constans-value.ts`)
|
||||
|
||||
```typescript
|
||||
PADDING_INLINE = 16 // use selectively, not on every screen by default
|
||||
PADDING_EXTRA_SMALL = 10
|
||||
PADDING_SMALL = 12
|
||||
PADDING_MEDIUM = 16
|
||||
PADDING_LARGE = 20
|
||||
|
||||
OS_ANDROID_HEIGHT = 60 / OS_IOS_HEIGHT = 80
|
||||
OS_ANDROID_PADDING_TOP = 6 / OS_IOS_PADDING_TOP = 12
|
||||
|
||||
TEXT_SIZE_SMALL = 12 / MEDIUM = 14 / LARGE = 16 / XLARGE = 18
|
||||
PAGINATION_DEFAULT_TAKE = 10
|
||||
DRAWER_HEIGHT = 500
|
||||
RADIUS_BUTTON = 50
|
||||
```
|
||||
|
||||
```typescript
|
||||
// constants/color-palet.ts
|
||||
MainColor.darkblue = "#001D3D" // user app primary
|
||||
AdminColor.bgAdmin = "#182c47" // admin panel background
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Known Issues
|
||||
|
||||
### iOS Maplibre crash — "Attempt to recycle a mounted view"
|
||||
|
||||
Never conditionally render `PointAnnotation`. Control visibility via opacity instead:
|
||||
|
||||
```typescript
|
||||
// ✅ correct
|
||||
<PointAnnotation coordinate={coordinate}>
|
||||
<View style={{ opacity: selectedLocation ? 1 : 0 }}>
|
||||
<SelectedLocationMarker />
|
||||
</View>
|
||||
</PointAnnotation>
|
||||
|
||||
// ❌ crashes iOS
|
||||
{selectedLocation && <PointAnnotation ... />}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Known Typos — Do NOT fix unless asked
|
||||
|
||||
| Path | Typo |
|
||||
|---|---|
|
||||
| `constants/constans-value.ts` | `constans` |
|
||||
| `constants/base-url-api-strorage.ts` | `strorage` |
|
||||
| `screens/Invesment/` | `Invesment` |
|
||||
| `screens/Portofolio/` | `Portofolio` |
|
||||
| `screens/UserSeach/` | `UserSeach` |
|
||||
|
||||
---
|
||||
|
||||
## Environment Variables (`.env`)
|
||||
|
||||
```env
|
||||
API_BASE_URL=https://your-api-url.com
|
||||
BASE_URL=https://your-app-url.com
|
||||
DEEP_LINK_URL=hipmimobile://
|
||||
```
|
||||
|
||||
Accessed via: `Constants.expoConfig?.extra?.API_BASE_URL`
|
||||
|
||||
---
|
||||
|
||||
## New Screen Checklist
|
||||
|
||||
1. `service/api-admin/api-xxx.ts` — API function with `page` param
|
||||
2. `screens/Admin/Feature/ScreenXXX.tsx` — screen with `usePagination` + `OS_Wrapper`
|
||||
3. `screens/Admin/Feature/BoxXXX.tsx` — card component (optional)
|
||||
4. `app/(application)/admin/feature/index.tsx` — thin route file
|
||||
17
docs/README.md
Normal file
17
docs/README.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# Dokumentasi HIPMI Mobile
|
||||
|
||||
## Struktur Folder
|
||||
|
||||
| Folder | Isi |
|
||||
|---|---|
|
||||
| [architecture/](./architecture/) | Referensi arsitektur, komponen, dan implementasi |
|
||||
| [testing/](./testing/) | Panduan dan catatan testing fitur |
|
||||
| [notes/](./notes/) | Catatan development dan changelog |
|
||||
| [ai/](./ai/) | Prompt dan konfigurasi AI tools |
|
||||
| [tasks/](./tasks/) | Task list development |
|
||||
|
||||
## Referensi Cepat
|
||||
|
||||
- [OS_Wrapper Quick Reference](./architecture/OS-Wrapper-Quick-Reference.md)
|
||||
- [Admin Folder Structure](./architecture/admin-folder-structure.md)
|
||||
- [Change Log](./notes/CHANGE_LOG.md)
|
||||
Reference in New Issue
Block a user