Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
ff3b302
chore: initialize server project with dependencies and .env setup
fadhalshulhan Apr 29, 2025
6565874
feat: add Google Sign-In authentication with JWT
fadhalshulhan Apr 29, 2025
f3da467
feat: add CRUD endpoints for Plant
fadhalshulhan Apr 29, 2025
a050d08
chore: setup client project with Vite, React, and Tailwind CSS
fadhalshulhan Apr 29, 2025
04d1c32
feat: setup Redux with auth and plant slices
fadhalshulhan Apr 29, 2025
9206e89
feat: add OpenAI integration for plant care recommendation
fadhalshulhan Apr 29, 2025
2108dc3
feat: integrate third-party APIs (OpenWeatherMap for weather, Nodemai…
fadhalshulhan Apr 29, 2025
c425e04
feat: setup routing, navbar, and login page with Google Sign-In
fadhalshulhan Apr 30, 2025
7f4b3bc
feat: add plant management page with form and card components
fadhalshulhan Apr 30, 2025
7f5a66f
feat: add care recommendation page with OpenAI and weather integration
fadhalshulhan Apr 30, 2025
151951f
feat: add email reminder using Nodemailer when adding a plant and
fadhalshulhan Apr 30, 2025
727f1ec
docs: add API documentation for all endpoints
fadhalshulhan Apr 30, 2025
78efeac
feat(client,server): enhance frontend and backend with new features, …
fadhalshulhan May 1, 2025
b86d092
fix add limit size
fadhalshulhan May 1, 2025
131f82c
fix add limit size
fadhalshulhan May 1, 2025
a8f7df4
fix size limit in front end
fadhalshulhan May 1, 2025
e29d104
add register logiin
fadhalshulhan May 2, 2025
511c73c
update docs
fadhalshulhan May 2, 2025
a064441
feat: add species prediction, Gmail OAuth, and email reminders
fadhalshulhan May 9, 2025
2da2d02
update add alert when add plant success and notify user for content s…
fadhalshulhan May 9, 2025
7e8a031
fix double submit and sort card
fadhalshulhan May 9, 2025
b2d49d8
add 503 service unavailable AI
fadhalshulhan May 9, 2025
99c132a
add validation when min. 3 karakter input
fadhalshulhan May 9, 2025
f73b9b7
fix validation:
fadhalshulhan May 9, 2025
c316ec3
fix auth to app password
fadhalshulhan May 19, 2025
77fc906
update depedency
fadhalshulhan May 19, 2025
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
12 changes: 12 additions & 0 deletions client/.firebase/hosting.ZGlzdA.cache
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
vite.svg,1746068265476,699a02e0e68a579f687d364bbbe7633161244f35af068220aee37b1b33dfb3c7
site.webmanifest,1746065994692,65748f57e3a355ca3b5213dc1a8ab66a2a605f966aa3576f0c482129ce284b00
favicon.ico,1746065994683,75e22ef9fcefab4928e9fe1d401f9ebdb68b3d3370404682de8a528bfb4874f6
favicon-32x32.png,1746065994674,e37f14eb2b82c2bc191e1a8837c4737bb67d56bd0b9d28b519d85b454da929e9
favicon-16x16.png,1746065994678,06963e1fa50ae6d3978f2e91ae23815b36ce872de7d0ebbe2b4c66cf511bc963
apple-touch-icon.png,1746065994664,540d7e5277ef85ccccd1370af5ee7ef1cf1cf906f2972c61b17a0725de581cb0
android-chrome-512x512.png,1746065994707,11f008c74174282563f165a6f5dd5c3d7edbd344fb30c616119de37d8ec13034
android-chrome-192x192.png,1746065994700,eec91f75fe328b964e7ca7831ff01f7e64cd95aeab8261ea75dcf998f57d2d24
index.html,1746804219101,dad4cad89c989a5fad7e970459935c6053ea94f947d13007e077bff0f85638c4
assets/index-CkHff6yF.css,1746804219103,86b1d39d442a2137e714c5f6caec65a1279c89e46dc69eea2697bf2743fb736a
assets/logo-EBl5TyLI.jpg,1746804219103,fbe39c273fd998f7cf0def096a596c0c494307af8f758a91da479f76a42a2fe4
assets/index-iqPI0vOe.js,1746804219103,bf90c887d9e6c2059f38d65c74ea8aa5903faf4a5c1c324ba11b09d3d521aa74
5 changes: 5 additions & 0 deletions client/.firebaserc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"projects": {
"default": "plant-planner-1274d"
}
}
27 changes: 27 additions & 0 deletions client/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
.env
.env.development
.env.production
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
156 changes: 156 additions & 0 deletions client/README FE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
# Plant Planner - Frontend

Plant Planner adalah platform berkebun cerdas berbasis AI yang membantu pengguna merawat tanaman mereka melalui antarmuka yang ramah pengguna dan fitur-fitur cerdas.

## ✨ Fitur Utama

- 🔐 **Autentikasi Google**: Login menggunakan Google OAuth untuk akses yang aman dan cepat.
- 🪴 **CRUD Manajemen Tanaman**: Tambah, ubah, hapus, dan lihat daftar tanaman pengguna.
- 🧠 **Rekomendasi Perawatan Tanaman Berbasis AI**: Dapatkan saran perawatan dari OpenAI berdasarkan spesies tanaman dan kondisi lingkungan.
- 🌤️ **Informasi Cuaca Lokal**: Integrasi dengan OpenWeatherMap API untuk menampilkan cuaca berdasarkan lokasi.
- 🖼️ **Upload & Hapus Foto Tanaman**: Unggah dan kelola foto tanaman menggunakan Cloudinary.
- 📧 **Pengingat Perawatan via Email**: Notifikasi otomatis untuk jadwal perawatan tanaman.
- 👤 **Manajemen Profil**: Lihat dan kelola informasi pengguna.

## 📁 Struktur Routes Frontend

Berdasarkan kode `App.jsx`, berikut adalah struktur routes frontend:

| Path | Komponen | Keterangan | Proteksi |
| ----------------- | ---------------- | -------------------------------------- | -------------- |
| `/` | `Home` | Halaman beranda | Tidak |
| `/login` | `Login` | Halaman login menggunakan Google OAuth | Tidak |
| `/register` | `Register` | Halaman registrasi pengguna | Tidak |
| `/plants` | `Plants` | Daftar tanaman pengguna | Ya (Protected) |
| `/recommendation` | `Recommendation` | Rekomendasi perawatan dari AI | Ya (Protected) |
| `/profile` | `Profile` | Halaman profil pengguna | Ya (Protected) |

### Catatan Routes

- Semua route di dalam `Layout` memiliki tampilan konsisten (misalnya, header, footer, atau sidebar).
- Route dengan `ProtectedRoute` memerlukan autentikasi (JWT token valid). Pengguna yang tidak login akan diarahkan ke `/login`.
- Route `/plants/:id` (untuk detail dan edit tanaman) dan `/add` (tambah tanaman) tidak terlihat di kode `App.jsx`, tetapi kemungkinan diimplementasikan di dalam komponen `Plants` atau sebagai sub-route.

## 🛠️ Teknologi Digunakan

- **React + Vite**: Framework frontend dan bundler untuk performa cepat.
- **Tailwind CSS**: Styling utility-first untuk desain responsif dan cepat.
- **Redux Toolkit**: Manajemen state global, termasuk autentikasi dan data pengguna.
- **Axios**: HTTP client untuk komunikasi dengan backend API.
- **JWT Authentication**: Autentikasi berbasis token untuk akses aman ke endpoint terproteksi.
- **Cloudinary**: Layanan untuk upload dan manajemen foto tanaman.
- **OpenAI API**: Menghasilkan rekomendasi perawatan tanaman berbasis AI.
- **OpenWeatherMap API**: Menyediakan data cuaca lokal.

## 🗂️ Struktur Kode Frontend

### Komponen Utama

- **App.jsx**: Komponen utama yang mengatur routing dan inisialisasi sesi autentikasi.
- **Layout.jsx**: Komponen wrapper untuk menyediakan struktur UI konsisten (misalnya, navbar, footer).
- **ProtectedRoute.jsx**: Komponen untuk melindungi route yang memerlukan autentikasi.
- **Pages**:
- `Home`: Menampilkan beranda.
- `Login`: Form login dengan Google OAuth.
- `Register`: Form registrasi pengguna.
- `Plants`: Daftar tanaman (kemungkinan termasuk sub-route untuk detail dan tambah tanaman).
- `Recommendation`: Form dan hasil rekomendasi perawatan dari AI.
- `Profile`: Informasi dan pengaturan pengguna.

### Redux State Management

- **authSlice**: Mengelola state autentikasi, termasuk:
- `initialized`: Status inisialisasi sesi.
- `user`: Data pengguna (userId, email, name, picture).
- `token`: JWT token untuk autentikasi.
- **restoreSession**: Action untuk memeriksa dan memulihkan sesi pengguna saat aplikasi dimuat.

### Flow Autentikasi

1. Saat aplikasi dimuat, `useEffect` di `App.jsx` memanggil `restoreSession` untuk memeriksa token di local storage atau session.
2. Jika sesi belum diinisialisasi (`initialized: false`), tampilkan loading screen.
3. Jika token valid, pengguna dapat mengakses route terproteksi (`/plants`, `/recommendation`, `/profile`).
4. Jika tidak ada token atau token tidak valid, pengguna diarahkan ke `/login`.

## 📋 Detail Implementasi

### Autentikasi

- **Google OAuth**: Menggunakan Google Sign-In SDK untuk mendapatkan `googleToken`, yang dikirim ke backend (`POST /auth/google`) untuk mendapatkan JWT token.
- **Registrasi/Login Manual**: Form di `/register` dan `/login` mengirimkan data ke `POST /auth/register` dan `POST /auth/login`.
- **Sesi**: Token disimpan di Redux state dan local storage. `restoreSession` memeriksa token saat aplikasi dimuat.
- **Refresh Token**: Jika token kadaluarsa, panggil `POST /auth/refresh-token` untuk memperbarui token.

### Manajemen Tanaman

- **Daftar Tanaman**: Komponen `Plants` mengambil data dari `GET /plants` dan menampilkan daftar tanaman.
- **Tambah Tanaman**: Form di `/add` (atau sub-route di `Plants`) mengirimkan data ke `POST /plants`.
- **Edit Tanaman**: Detail tanaman di `/plants/:id` memungkinkan pembaruan via `PUT /plants/:id`.
- **Hapus Tanaman**: Tombol hapus memanggil `DELETE /plants/:id`.
- **Foto Tanaman**: Upload foto via `POST /plants/:plantId/photo` (form-data) dan hapus via `DELETE /plants/photo/:photoId`.

### Rekomendasi AI

- Komponen `Recommendation` mengirimkan data (species, location, light, temperature) ke `POST /recommendation/care` dan menampilkan hasil rekomendasi.

### Cuaca

- Komponen `Weather` (atau bagian dari komponen lain) memanggil `GET /weather?city={city}` untuk menampilkan informasi cuaca lokal.

## ⚙️ Setup dan Pengembangan

### Prasyarat

- Node.js (versi 16 atau lebih baru)
- Akun Cloudinary untuk upload foto
- API Key OpenAI untuk rekomendasi
- API Key OpenWeatherMap untuk cuaca
- Backend Plant Planner berjalan di `http://localhost:3000/api`

### Instalasi

1. Clone repository frontend.
2. Jalankan `npm install` untuk menginstal dependensi.
3. Buat file `.env` dengan variabel berikut:
```
VITE_GOOGLE_CLIENT_ID=your_google_client_id
VITE_API_URL=http://localhost:3000/api
VITE_CLOUDINARY_CLOUD_NAME=your_cloudinary_cloud_name
VITE_OPENAI_API_KEY=your_openai_api_key
VITE_OPENWEATHERMAP_API_KEY=your_openweathermap_api_key
```
4. Jalankan `npm run dev` untuk memulai server pengembangan.

### Struktur Folder

```
src/
├── components/ # Komponen reusable (Layout, ProtectedRoute, dll.)
├── pages/ # Komponen halaman (Home, Login, Plants, dll.)
├── redux/ # Redux slices dan store
├── assets/ # Gambar, font, dll.
├── App.jsx # Komponen utama dan routing
├── main.jsx # Entry point
```

## 📝 Catatan Pengembangan

- **Responsivitas**: Gunakan Tailwind CSS untuk memastikan antarmuka responsif di desktop dan mobile.
- **Error Handling**: Tampilkan pesan error yang ramah pengguna (misalnya, "Token kadaluarsa, silakan login ulang") untuk setiap kegagalan API.
- **Loading States**: Tambahkan indikator loading untuk setiap panggilan API (misalnya, saat mengambil daftar tanaman atau rekomendasi).
- **Keamanan**: Jangan simpan token atau data sensitif di tempat yang tidak aman. Gunakan `localStorage` dengan hati-hati dan pertimbangkan `HttpOnly` cookies jika memungkinkan.
- **Optimasi**: Gunakan lazy loading untuk komponen besar (misalnya, `Recommendation`) dan optimalkan panggilan API dengan caching jika diperlukan.

## 🔗 Integrasi dengan Backend

- **Base URL**: `http://localhost:3000/api`
- **Autentikasi**: Kirim header `Authorization: Bearer <token>` untuk endpoint terproteksi.
- **Error Handling**: Tangani status HTTP seperti `401` (redirect ke login), `400` (tampilkan error spesifik), dan `500` (tampilkan error umum).
- **Form-data**: Untuk upload foto, gunakan `FormData` dengan Axios.

## 🚀 Fitur yang Dapat Ditambahkan

- **Pencarian Tanaman**: Filter atau cari tanaman berdasarkan nama atau spesies.
- **Notifikasi Real-time**: Gunakan WebSocket untuk pengingat perawatan.
- **Dashboard**: Ringkasan tanaman, cuaca, dan rekomendasi di beranda.
- **Lokalasi Otomatis**: Deteksi lokasi pengguna untuk cuaca menggunakan Geolocation API.
33 changes: 33 additions & 0 deletions client/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'

export default [
{ ignores: ['dist'] },
{
files: ['**/*.{js,jsx}'],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
parserOptions: {
ecmaVersion: 'latest',
ecmaFeatures: { jsx: true },
sourceType: 'module',
},
},
plugins: {
'react-hooks': reactHooks,
'react-refresh': reactRefresh,
},
rules: {
...js.configs.recommended.rules,
...reactHooks.configs.recommended.rules,
'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }],
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
},
]
16 changes: 16 additions & 0 deletions client/firebase.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"hosting": {
"public": "dist",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [
{
"source": "**",
"destination": "/index.html"
}
]
}
}
25 changes: 25 additions & 0 deletions client/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />

<link rel="icon" href="/favicon.ico" />
<link rel="shortcut icon" href="/favicon.ico" />
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
<link rel="manifest" href="/site.webmanifest" />
<script src="https://accounts.google.com/gsi/client" async defer></script>
<link
href="https://fonts.googleapis.com/icon?family=Material+Icons+Round"
rel="stylesheet"
/>

<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Plant Planner</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
Loading