duit/LEARNING_MATERIALS.md

570 lines
13 KiB
Markdown
Raw Permalink Normal View History

# Finance Tracker - Materi Pembelajaran React Native
Project ini adalah aplikasi penghitung income dan expense keuangan untuk pembelajaran React Native. Setiap commit merepresentasikan satu tahap pembelajaran yang dapat diikuti oleh murid dan pengajar.
---
## Prerequisites
Sebelum memulai, pastikan komputer Anda sudah terinstall:
1. **Node.js** (versi 18 atau terbaru)
- Download: https://nodejs.org
- Cek: `node --version`
2. **Expo CLI**
```bash
npm install -g expo-cli
```
3. **Code Editor** (VS Code direkomendasikan)
- Download: https://code.visualstudio.com
4. **Untuk Running di Android:**
- Android Studio (dengan SDK)
- Atau gunakan Expo Go di smartphone
---
## Struktur Folder Project
```
duit/
├── app/ # File routing (expo-router)
│ ├── _layout.tsx # Root layout
│ └── (tabs)/ # Tab navigation
│ ├── _layout.tsx # Tab config
│ ├── index.tsx # Home screen
│ └── explore.tsx # Stats screen
├── components/ # Komponen React Native
│ ├── Header.tsx # Header component
│ ├── BalanceCard.tsx # Balance display
│ ├── TransactionForm.tsx # Input form
│ └── TransactionList.tsx # Transaction list
├── hooks/ # Custom hooks
│ └── useTransactions.ts # Data management hook
├── types/ # TypeScript types
│ └── index.ts # Transaction interface
├── utils/ # Utility functions
│ └── helpers.ts # Helper functions
├── constants/ # Konstanta
│ └── theme.ts # Colors & fonts
├── package.json
└── LEARNING_MATERIALS.md
```
---
## Daftar Commit Pembelajaran
### Fase 1: Setup & Types (Commit 1-3)
#### Commit 1: Setup Project
**Topik:** Install dependencies, TypeScript interfaces
**Materi yang dipelajari:**
- Cara install package dengan npm
- TypeScript interface untuk mendefinisikan bentuk data
- Export/import module
**Code penting:**
```typescript
// types/index.ts
export interface Transaction {
id: string;
amount: number;
description: string;
type: 'income' | 'expense';
category: string;
date: string;
}
```
**Poin pembelajaran:**
- Interface adalah "blueprint" untuk object
- Tipe data yang tersedia: string, number, boolean
---
#### Commit 2: Theme Constants
**Topik:** Konstanta warna dan font
**Materi yang dipelajari:**
- Mendefinisikan konstanta di React Native
- Konfigurasi tema aplikasi
**Code penting:**
```typescript
// constants/theme.ts
export const COLORS = {
income: '#4CAF50',
expense: '#F44336',
background: '#F5F5F5',
card: '#FFFFFF',
text: '#333333',
primary: '#2196F3',
} as const;
```
**Poin pembelajaran:**
- `as const` membuat object jadi readonly
- Gunakan konsistensi warna di seluruh app
---
#### Commit 3: Helper Functions
**Topik:** Fungsi utility
**Materi yang dipelajari:**
- Membuat fungsi helper yang reusable
- Formatting angka dan tanggal
- Array reduce untuk kalkulasi
**Code penting:**
```typescript
// utils/helpers.ts
export const formatRupiah = (amount: number): string => {
return new Intl.NumberFormat('id-ID', {
style: 'currency',
currency: 'IDR',
}).format(amount);
};
export const calculateBalance = (transactions: Transaction[]): BalanceInfo => {
const income = transactions
.filter((t) => t.type === 'income')
.reduce((sum, t) => sum + t.amount, 0);
// ...
};
```
**Poin pembelajaran:**
- `Intl.NumberFormat` untuk mata uang Indonesia
- `reduce` untuk menjumlahkan array
- `filter` untuk menyaring array
---
### Fase 2: Components (Commit 4-7)
#### Commit 4: Header Component
**Topik:** Komponen Pertama
**Materi yang dipelajari:**
- Cara membuat komponen React Native
- View, Text, StyleSheet
- Interface props
**Code penting:**
```typescript
// components/Header.tsx
interface HeaderProps {
title: string;
}
export const Header: React.FC<HeaderProps> = ({ title }) => {
return (
<View style={styles.container}>
<Text style={styles.title}>{title}</Text>
</View>
);
};
```
**Poin pembelajaran:**
- Komponen adalah fungsi yang return JSX
- Props digunakan untuk data dinamis
- `React.FC` adalah type untuk functional component
---
#### Commit 5: BalanceCard Component
**Topik:** Props dan conditional styling
**Materi yang dipelajari:**
- Menerima object sebagai props
- Conditional styling (warna berbeda untuk income/expense)
**Code penting:**
```typescript
interface BalanceCardProps {
balance: BalanceInfo;
}
export const BalanceCard: React.FC<BalanceCardProps> = ({ balance }) => {
return (
<View>
<Text style={[styles.amount, styles.income]}>
+{formatRupiah(balance.income)}
</Text>
</View>
);
};
```
**Poin pembelajaran:**
- Destructure props dengan `{ balance }`
- Conditional class dengan array `[styles.base, isActive && styles.active]`
---
#### Commit 6: TransactionForm Component
**Topik:** Form input dengan useState
**Materi yang dipelajari:**
- useState untuk form inputs
- TextInput component
- TouchableOpacity untuk button
- ScrollView horizontal
**Code penting:**
```typescript
// components/TransactionForm.tsx
const [amount, setAmount] = useState('');
const [description, setDescription] = useState('');
const [type, setType] = useState<'income' | 'expense'>('expense');
<TextInput
style={styles.input}
placeholder="Jumlah (Rp)"
value={amount}
onChangeText={setAmount}
keyboardType="numeric"
/>
<TouchableOpacity onPress={() => setType('expense')}>
<Text>Pengeluaran</Text>
</TouchableOpacity>
```
**Poin pembelajaran:**
- `useState` menyimpan state komponen
- `onChangeText` menangkap input teks
- `keyboardType="numeric"` untuk number only
- TouchableOpacity = button yang bisa ditekan
---
#### Commit 7: TransactionList Component
**Topik:** FlatList dan rendering
**Materi yang dipelajari:**
- FlatList untuk list panjang
- renderItem function
- Empty state handling
**Code penting:**
```typescript
// components/TransactionList.tsx
<FlatList
data={transactions}
keyExtractor={(item) => item.id}
renderItem={renderItem}
scrollEnabled={false}
/>
if (transactions.length === 0) {
return <View style={styles.empty}>...</View>;
}
```
**Poin pembelajaran:**
- FlatList lebih efficient dari map
- `keyExtractor` untuk key unik
- `renderItem` menerima object `{ item }`
---
### Fase 3: State Management (Commit 8-10)
#### Commit 8: useTransactions Hook
**Topik:** Custom hooks
**Materi yang dipelajari:**
- Membuat custom hook
- useState dan useEffect
- Load data dari AsyncStorage
**Code penting:**
```typescript
// hooks/useTransactions.ts
export const useTransactions = () => {
const [transactions, setTransactions] = useState<Transaction[]>([]);
const [loading, setLoading] = useState(true);
const loadTransactions = async () => {
const stored = await AsyncStorage.getItem(STORAGE_KEY);
if (stored) setTransactions(JSON.parse(stored));
};
useEffect(() => {
loadTransactions();
}, []);
return { transactions, loading };
};
```
**Poin pembelajaran:**
- Hook adalah fungsi dengan "use" prefix
- useEffect untuk side effects (API calls)
- AsyncStorage untuk persistence lokal
---
#### Commit 9: addTransaction
**Topik:** State update dengan callback
**Materi yang dipelajari:**
- Menambah item ke state
- Callback function
- useCallback untuk optimisasi
**Code penting:**
```typescript
const addTransaction = useCallback((transaction: Transaction) => {
setTransactions((prev) => {
const updated = [transaction, ...prev];
AsyncStorage.setItem(STORAGE_KEY, JSON.stringify(updated));
return updated;
});
}, []);
```
**Poin pembelajaran:**
- Gunakan functional update `setTransactions(prev => ...)`
- Selalu simpan ke storage setelah update
---
#### Commit 10: deleteTransaction
**Topik:** Hapus item dari state
**Materi yang dipelajari:**
- Filter untuk hapus item
- Update berdasarkan id
**Code penting:**
```typescript
const deleteTransaction = useCallback((id: string) => {
setTransactions((prev) => {
const updated = prev.filter((t) => t.id !== id);
AsyncStorage.setItem(STORAGE_KEY, JSON.stringify(updated));
return updated;
});
}, []);
```
**Poin pembelajaran:**
- `filter` mengembalikan array baru (tidak mutate)
- Compare dengan `!==` untuk hapus berdasarkan id
---
### Fase 4: Screen Integration (Commit 11-15)
#### Commit 11: HomeScreen
**Topik:** Menggabungkan komponen
**Materi yang dipelajari:**
- Import dan gunakan komponen
- Loading state
- ScrollView
**Code penting:**
```typescript
// screens/HomeScreen.tsx
export default function HomeScreen() {
const { transactions, loading, addTransaction, deleteTransaction } = useTransactions();
const balance = calculateBalance(transactions);
if (loading) {
return <ActivityIndicator />;
}
return (
<View>
<Header title="Pengeluaran Kita" />
<ScrollView>
<BalanceCard balance={balance} />
<TransactionForm onAdd={addTransaction} />
<TransactionList transactions={transactions} onDelete={deleteTransaction} />
</ScrollView>
</View>
);
}
```
**Poin pembelajaran:**
- Custom hook return multiple values dengan destructuring
- ActivityIndicator untuk loading state
- ScrollView untuk konten panjang
---
#### Commit 12-15: App Integration
**Topik:** Expo Router & Navigation
**Materi yang dipelajari:**
- File-based routing dengan expo-router
- Tab navigation
- Layout configuration
---
### Fase 5: Enhancements (Commit 16-21)
Topics tambahan:
- Categories management
- Form validation
- Code refactoring
---
## Cara Menggunakan untuk Pembelajaran
### Cara 1: Ikuti Commit Satu per Satu
1. **Clone repository:**
```bash
git clone <repo-url>
cd duit
```
2. **Lihat semua commits:**
```bash
git log --oneline
```
3. **Pergi ke commit tertentu:**
```bash
git checkout <commit-hash>
```
4. **Install dan run:**
```bash
npm install
npx expo start
```
**⚠️ PENTING: Urutan Commit yang harus Diperhatikan**
Beberapa commit memiliki dependensi. Berikut urutannya:
| Jika ingin belajar | Pastikan sudah checkout ke commit |
|-----------------|------------------------------|
| Commit 4-7 (Components) | Setelah commit 3 |
| Commit 11+ (HomeScreen) | Setelah commit 10 (useTransactions) |
| Commit 14 (Stats Screen) | Setelah commit 10 (useTransactions) |
| Commit 18+ (Categories) | Setelah commit 17 |
**Jangan langsung checkout ke commit tinggi** tanpa mengikuti urutan, karena akan terjadi error (beberapa komponen/hooks belum tersedia).
### Cara 2: Belajar dari Kode
1. Clone repository di commit terakhir
2. Baca kode di setiap file
3. Pahami hubungan antar komponen
4. Modifikasi untuk latihan
### Cara 3: Latihan Pengembangan
1. Di commit terakhir, tambahkan fitur:
- Filter transaksi per kategori
- Edit transaksi yang sudah ada
- Export data ke CSV
- Dark mode
---
## Cara Run Aplikasi
### Di Emulator Android
```bash
npx expo start --android
```
### Di Emulator iOS (Mac only)
```bash
npx expo start --ios
```
### Di Browser (Web)
```bash
npx expo start --web
```
### Di Smartphone
1. Install "Expo Go" dari App Store/Play Store
2. Scan QR code dari terminal
---
## Debugging Tips
1. **React Native Debugger**
- iOS: `Cmd + D`
- Android: `Cmd + M` atau `Ctrl + M`
- Enable "Debug JS Remotely"
2. **Console.log**
```typescript
console.log('Data:', transactions);
```
3. **Error Boundary**
- Perhatikan error merah di emulator
- Check terminal untuk stack trace
---
## Fitur Aplikasi
- ✅ Tambah income/pengeluaran
- ✅ Lihat saldo total
- ✅ Riwayat transaksi
- ✅ Hapus transaksi
- ✅ Kategori transaksi
- ✅ Simpan data lokal (AsyncStorage)
- ✅ Tab navigation (Keuangan & Statistik)
- ✅ Ringkasan bulanan
- ✅ Kategori pengeluaran terbesar
---
## Daftar Commit Lengkap
| # | Commit Hash | Deskripsi |
|---|------------|----------|
| 1 | feat: setup project and add types | Install AsyncStorage, Transaction interface |
| 2 | feat: add theme constants | COLORS, FONTS |
| 3 | feat: add helper utility functions | formatRupiah, calculateBalance |
| 4 | feat: create Header component | Komponen title |
| 5 | feat: create BalanceCard component | Tampilan saldo |
| 6 | feat: create TransactionForm component | Form input |
| 7 | feat: create TransactionList component | List riwayat |
| 8 | feat: create useTransactions hook | Load data |
| 9 | feat: add addTransaction function | Tambah transaksi |
| 10 | feat: add deleteTransaction function | Hapus transaksi |
| 11 | feat: create HomeScreen | Gabung komponen |
| 12 | feat: update index to use HomeScreen | Entry point |
| 13 | feat: configure tab navigation | Tab config |
| 14 | feat: create Explore/StatsScreen | Statistik |
| 15 | feat: simplify root layout | Layout utama |
| 16 | docs: add learning materials | Dokumentasi |
| 17 | feat: add CATEGORIES constant | Categories array |
| 18 | refactor: use CATEGORIES from types | Import categories |
| 19 | refactor: add getCategoryLabel helper | Helper function |
| 20 | feat: add form validation | Alert, validation |
---
## Referensi
- [React Native Docs](https://reactnative.dev/docs/getting-started)
- [Expo Docs](https://docs.expo.dev)
- [TypeScript Handbook](https://www.typescriptlang.org/docs/)
---
**Happy Learning! 🚀**