diff --git a/TASKS/crowdfunding-redesign.md b/TASKS/crowdfunding-redesign.md
new file mode 100644
index 0000000..f990431
--- /dev/null
+++ b/TASKS/crowdfunding-redesign.md
@@ -0,0 +1,337 @@
+# Crowdfunding Page Redesign - Modern UI Enhancement
+
+## 📋 Ringkasan Task
+Redesign halaman Crowdfunding (`app/(application)/(user)/crowdfunding/index.tsx`) untuk menciptakan tampilan yang lebih modern, menarik, dan user-friendly dengan visual hierarchy yang lebih baik.
+
+---
+
+## 🎯 Tujuan
+1. Meningkatkan visual appeal dengan desain card yang modern
+2. Memperbaiki spacing dan layout untuk readability yang lebih baik
+3. Menambahkan elemen visual (icon, color accent) untuk navigasi yang lebih intuitif
+4. Menciptakan konsistensi dengan design system aplikasi HIPMI
+
+---
+
+## 📁 File yang Terlibat
+
+### File Utama
+- **Target**: `app/(application)/(user)/crowdfunding/index.tsx`
+
+### Komponen yang Mungkin Digunakan
+- `ViewWrapper` - Wrapper utama
+- `StackCustom` - Layout vertikal
+- `Grid` & `Grid.Col` - Layout horizontal
+- `TextCustom` - Typography
+- `BaseBox` / `AdminBasicBox` - Card container
+- `ClickableCustom` - Interactive element
+- `Feather` / `Ionicons` - Icons
+
+### Constants
+- `MainColor` - Color palette
+- `ICON_SIZE_SMALL`, `ICON_SIZE_BASE` - Icon sizing
+
+### Assets
+- `@/assets/images/constants/crowd-hipmi.png` - Header image
+
+---
+
+## 🔍 Analisis Kondisi Saat Ini
+
+### Kelemahan Design Sekarang
+1. **Header Image**
+ - Plain image tanpa overlay atau title
+ - Tidak ada visual hierarchy
+
+2. **Card List**
+ - BaseBox terlalu simple, kurang depth
+ - Tidak ada shadow atau elevation
+ - Border radius mungkin kurang smooth
+ - Spacing antar elemen kurang konsisten
+
+3. **Typography**
+ - Judul dan deskripsi kurang kontras
+ - Tidak ada visual emphasis yang kuat
+
+4. **Navigation**
+ - Chevron icon terlalu plain
+ - Tidak ada visual feedback saat hover/press
+
+5. **Color Usage**
+ - Kurang color accent untuk membedakan sections
+ - Monoton dengan warna yang ada
+
+---
+
+## 🎨 Rencana Desain
+
+### 1. Header Section Enhancement
+```
+┌─────────────────────────────────────┐
+│ [Hero Image dengan Overlay] │
+│ ┌─────────────────────────────┐ │
+│ │ Crowdfunding │ │
+│ │ Platform Investasi & Donasi │ │
+│ └─────────────────────────────┘ │
+└─────────────────────────────────────┘
+```
+
+**Implementasi:**
+- Image dengan overlay gradient untuk text readability
+- Title "Crowdfunding" dengan subtitle
+- Rounded corners dengan overflow hidden
+- Height: ~180-200px
+
+### 2. Card Design Modern
+```
+┌─────────────────────────────────────┐
+│ [Icon] Investasi → │
+│ Deskripsi singkat... │
+│ (2-3 baris max) │
+└─────────────────────────────────────┘
+```
+
+**Implementasi:**
+- Card dengan:
+ - Background gradient atau solid color dengan tint
+ - Shadow/elevation untuk depth
+ - Border radius: 12-16px
+ - Padding: 16-20px
+ - Icon di kiri (Investasi & Donasi)
+ - Chevron di kanan dengan style yang lebih modern
+
+### 3. Icon Integration
+- **Investasi**: Icon grafik/trending (contoh: `trending-up`, `pie-chart`)
+- **Donasi**: Icon hati/tangan (contoh: `heart`, `hand-heart`)
+- Size: 40-48px untuk icon card
+- Background icon: Circle dengan color accent
+
+### 4. Color Scheme
+```
+Investasi:
+- Primary: Blue/Teal gradient
+- Accent: Soft blue background
+- Icon: White on blue
+
+Donasi:
+- Primary: Orange/Red gradient
+- Accent: Soft orange background
+- Icon: White on orange
+```
+
+### 5. Typography Hierarchy
+```
+Header Title: bold, x-large (20-22px)
+Header Subtitle: regular, small (14-15px), gray
+Card Title: bold, large (17-18px)
+Card Description: regular, base (14px), gray
+```
+
+### 6. Spacing & Layout
+```
+Container padding: 16px
+Card margin bottom: 12-16px
+Card internal padding: 16px
+Gap between elements: 8-12px
+```
+
+---
+
+## 📝 Breakdown Task
+
+### Task 1: Persiapan & Research
+- [ ] Review komponen yang tersedia di `components/`
+- [ ] Cek color palette di `constants/color-palet.ts`
+- [ ] Identifikasi icon yang tersedia (Feather, Ionicons)
+- [ ] Screenshot design sekarang untuk perbandingan
+
+### Task 2: Setup Structure
+- [ ] Buat constant untuk list menu (pindahkan dari component body)
+- [ ] Tambahkan icon mapping untuk setiap menu item
+- [ ] Setup color scheme untuk setiap card
+
+### Task 3: Header Redesign
+- [ ] Buat container dengan overflow hidden
+- [ ] Tambahkan image dengan overlay gradient
+- [ ] Tambahkan title "Crowdfunding" dengan text white
+- [ ] Tambahkan subtitle (opsional)
+- [ ] Test di berbagai ukuran layar
+
+### Task 4: Card Component
+- [ ] Buat custom card component atau modify BaseBox
+- [ ] Tambahkan shadow/elevation
+- [ ] Tambahkan border radius yang smooth
+- [ ] Setup gradient background (opsional)
+- [ ] Tambahkan visual feedback saat press
+
+### Task 5: Icon Integration
+- [ ] Pilih icon yang sesuai untuk setiap menu
+- [ ] Buat icon container dengan background color
+- [ ] Setup icon size dan positioning
+- [ ] Test visibility di berbagai device
+
+### Task 6: Typography & Content
+- [ ] Apply text hierarchy (title, subtitle, desc)
+- [ ] Truncate description jika terlalu panjang (max 2-3 baris)
+- [ ] Ensure text contrast yang baik
+- [ ] Test dengan text panjang
+
+### Task 7: Polish & Refinement
+- [ ] Adjust spacing dan padding
+- [ ] Test di light/dark mode (jika applicable)
+- [ ] Test di berbagai ukuran layar (responsive)
+- [ ] Add smooth transitions/animations
+
+### Task 8: Testing
+- [ ] Test navigation ke setiap halaman
+- [ ] Test di iOS simulator
+- [ ] Test di Android emulator
+- [ ] Test di device fisik (jika memungkinkan)
+- [ ] Check performance (no lag saat scroll)
+
+---
+
+## 💻 Implementation Guidelines
+
+### Code Structure Example
+```typescript
+// Constants
+const CROWDFUNDING_MENU = [
+ {
+ title: "Investasi",
+ desc: "Buat investasi dan jual beli saham lebih mudah dengan pengguna lain.",
+ path: "investment/(tabs)",
+ icon: "trending-up",
+ color: MainColor.blue,
+ gradient: ["#667eea", "#764ba2"],
+ },
+ // ...
+];
+
+// Component
+export default function Crowdfunding() {
+ const renderHeader = () => (
+
+
+
+ Crowdfunding
+ Platform Investasi & Donasi
+
+
+ );
+
+ const renderCard = (item: CrowdfundingMenuItem) => (
+
+
+
+
+
+ {item.title}
+ {item.desc}
+
+
+
+ );
+
+ return (
+
+
+ {renderHeader()}
+ {CROWDFUNDING_MENU.map(renderCard)}
+
+
+ );
+}
+```
+
+### Style Guidelines
+```typescript
+const styles = StyleSheet.create({
+ headerContainer: {
+ position: 'relative',
+ borderRadius: 16,
+ overflow: 'hidden',
+ marginBottom: 20,
+ },
+ headerOverlay: {
+ position: 'absolute',
+ bottom: 0,
+ left: 0,
+ right: 0,
+ padding: 16,
+ backgroundColor: 'rgba(0,0,0,0.6)',
+ },
+ card: {
+ backgroundColor: MainColor.white,
+ borderRadius: 16,
+ padding: 16,
+ marginBottom: 12,
+ elevation: 4,
+ shadowColor: '#000',
+ shadowOffset: { width: 0, height: 2 },
+ shadowOpacity: 0.1,
+ shadowRadius: 4,
+ },
+ iconContainer: {
+ width: 48,
+ height: 48,
+ borderRadius: 24,
+ alignItems: 'center',
+ justifyContent: 'center',
+ marginRight: 12,
+ },
+});
+```
+
+---
+
+## ✅ Acceptance Criteria
+
+### Visual
+- [ ] Header dengan overlay text yang readable
+- [ ] Card dengan shadow/elevation yang jelas
+- [ ] Icon untuk setiap menu item
+- [ ] Color accent yang berbeda untuk Investasi & Donasi
+- [ ] Typography hierarchy yang jelas
+
+### Functional
+- [ ] Navigation ke halaman tujuan berfungsi
+- [ ] Responsive di berbagai ukuran layar
+- [ ] No console errors atau warnings
+- [ ] Smooth scroll (60fps)
+
+### Code Quality
+- [ ] Code terorganisir dengan baik
+- [ ] Components terpisah untuk reusability
+- [ ] Constants untuk data statis
+- [ ] Comments untuk logic yang kompleks
+- [ ] TypeScript types yang proper
+
+---
+
+## 📊 Estimated Effort
+- **Complexity**: Low-Medium
+- **Time Estimate**: 2-3 jam
+- **Risk Level**: Low (tidak ada breaking changes)
+
+---
+
+## 🔗 References
+- Design Reference: `screens/Forum/ViewBeranda3.tsx` (untuk pagination pattern)
+- Color Palette: `constants/color-palet.ts`
+- Icons: Feather Icons, Ionicons
+- Components: `components/_ShareComponent/`
+
+---
+
+## 📝 Notes
+- Pastikan backward compatibility (tidak breaking existing features)
+- Test di device dengan screen size berbeda
+- Consider accessibility (text contrast, touch target size)
+- Jika ada time, tambahkan micro-interactions (scale on press, dll)
+
+---
+
+**Created**: 2026-03-25
+**Status**: Pending
+**Priority**: Medium
diff --git a/app/(application)/(user)/home.tsx b/app/(application)/(user)/home.tsx
index e2c01c7..a693c3d 100644
--- a/app/(application)/(user)/home.tsx
+++ b/app/(application)/(user)/home.tsx
@@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable react-hooks/exhaustive-deps */
-import { BasicWrapper, StackCustom, ViewWrapper } from "@/components";
+import { BasicWrapper, NewWrapper, StackCustom, ViewWrapper } from "@/components";
import AppHeader from "@/components/_ShareComponent/AppHeader";
import CustomSkeleton from "@/components/_ShareComponent/SkeletonCustom";
import { MainColor } from "@/constants/color-palet";
@@ -148,7 +148,7 @@ export default function Application() {
}}
/>
-
) : (
-
-
- {Array.from({ length: 4 }).map((e, index) => (
-
- ))}
-
-
+ null
+ //
+ //
+ // {Array.from({ length: 4 }).map((e, index) => (
+ //
+ // ))}
+ //
+ //
)
}
>
@@ -201,10 +202,10 @@ export default function Application() {
{data ? (
) : (
-
+
)}
-
+
>
);
}
diff --git a/app/(application)/(user)/portofolio/[id]/create.tsx b/app/(application)/(user)/portofolio/[id]/create.tsx
index e9f2ae4..bc52b95 100644
--- a/app/(application)/(user)/portofolio/[id]/create.tsx
+++ b/app/(application)/(user)/portofolio/[id]/create.tsx
@@ -1,5 +1,5 @@
-import { Admin_ScreenPortofolioCreate } from "@/screens/Portofolio/ScreenPortofolioCreate";
+import { ScreenPortofolioCreate } from "@/screens/Portofolio/ScreenPortofolioCreate";
export default function PortofolioCreate() {
- return ;
+ return ;
}
diff --git a/components/_ShareComponent/NewWrapper.tsx b/components/_ShareComponent/NewWrapper.tsx
index 2d7d56d..3748ece 100644
--- a/components/_ShareComponent/NewWrapper.tsx
+++ b/components/_ShareComponent/NewWrapper.tsx
@@ -19,6 +19,7 @@ import {
SafeAreaView,
} from "react-native-safe-area-context";
import type { ScrollViewProps, FlatListProps } from "react-native";
+import Spacing from "./Spacing";
// --- ✅ Tambahkan refreshControl ke BaseProps ---
interface BaseProps {
@@ -111,7 +112,6 @@ const NewWrapper = (props: NewWrapperProps) => {
return `${String(item.id)}-${index}`;
})
}
-
refreshControl={refreshControl} // ✅ dari BaseProps
onEndReached={listProps.onEndReached}
onEndReachedThreshold={0.5}
@@ -156,15 +156,27 @@ const NewWrapper = (props: NewWrapperProps) => {
{headerComponent}
)}
-
+
+
+ {renderContainer(staticProps.children)}
+
+
+
+
+ {/*
{renderContainer(staticProps.children)}
-
+ */}
{footerComponent ? (
@@ -205,6 +205,6 @@ export default function LoginView() {
setLoadingTerm={setLoadingTerm}
/>
-
+
);
}
diff --git a/screens/Forum/ViewBeranda3.tsx b/screens/Forum/ViewBeranda3.tsx
index 2d8c551..c57de32 100644
--- a/screens/Forum/ViewBeranda3.tsx
+++ b/screens/Forum/ViewBeranda3.tsx
@@ -18,7 +18,7 @@ import _ from "lodash";
import { useEffect, useState } from "react";
import { RefreshControl, TouchableOpacity, View } from "react-native";
-const PAGE_SIZE = 5;
+const PAGE_SIZE = 10;
export default function Forum_ViewBeranda3() {
const { user } = useAuth();
diff --git a/screens/Home/homeViewStyle.tsx b/screens/Home/homeViewStyle.tsx
index dac67ff..8949ca6 100644
--- a/screens/Home/homeViewStyle.tsx
+++ b/screens/Home/homeViewStyle.tsx
@@ -94,7 +94,7 @@ export const stylesHome = StyleSheet.create({
jobVacancyHeader: {
flexDirection: "row",
alignItems: "center",
- marginBottom: 16,
+ marginBottom: 20,
},
jobVacancyTitle: {
fontSize: 18,
diff --git a/screens/Home/tabSection.tsx b/screens/Home/tabSection.tsx
index 23c0a9f..0011a9b 100644
--- a/screens/Home/tabSection.tsx
+++ b/screens/Home/tabSection.tsx
@@ -5,7 +5,6 @@ import { router } from "expo-router";
import React from "react";
import { Text, TouchableOpacity, View } from "react-native";
-
const CustomTab = ({ icon, label, isActive, onPress }: ICustomTab) => (
(
>
@@ -30,8 +29,8 @@ const CustomTab = ({ icon, label, isActive, onPress }: ICustomTab) => (
export default function TabSection({ tabs }: { tabs: ITabs[] }) {
return (
<>
-
-
+
+
{tabs.map((e) => (
(null);
const [inputValue, setInputValue] = useState("");
@@ -72,7 +72,7 @@ export function Admin_ScreenPortofolioCreate() {
useCallback(() => {
onLoadMaster();
onLoadMasterSubBidangBisnis();
- }, [])
+ }, []),
);
const onLoadMaster = async () => {
@@ -97,7 +97,7 @@ export function Admin_ScreenPortofolioCreate() {
const handlerSelectedSubBidang = ({ id }: { id: string }) => {
const selectedList = subBidangBisnis?.filter(
- (item) => (item?.masterBidangBisnisId as any) === id
+ (item) => (item?.masterBidangBisnisId as any) === id,
);
setSelectedSubBidang(selectedList as any[]);
};
@@ -168,8 +168,7 @@ export function Admin_ScreenPortofolioCreate() {
.filter((option: any) => {
const selectedValues = listSubBidangSelected.map((s) => s.id);
return (
- option.id === item.id ||
- !selectedValues.includes(option.id)
+ option.id === item.id || !selectedValues.includes(option.id)
);
})
.map((e: any) => ({
@@ -188,7 +187,9 @@ export function Admin_ScreenPortofolioCreate() {
{
setListSubBidangSelected([
...listSubBidangSelected,
diff --git a/screens/UserSeach/MainView_V2.tsx b/screens/UserSeach/MainView_V2.tsx
index 9632072..a21c3c4 100644
--- a/screens/UserSeach/MainView_V2.tsx
+++ b/screens/UserSeach/MainView_V2.tsx
@@ -12,6 +12,7 @@ import {
ICON_SIZE_SMALL,
PAGINATION_DEFAULT_TAKE,
} from "@/constants/constans-value";
+import { createPaginationComponents } from "@/helpers/paginationHelpers";
import { usePagination } from "@/hooks/use-pagination";
import { apiAllUser } from "@/service/api-client/api-user";
import { Ionicons } from "@expo/vector-icons";
@@ -19,21 +20,89 @@ import { router, useFocusEffect } from "expo-router";
import _ from "lodash";
import { useCallback, useRef, useState } from "react";
import { RefreshControl, View } from "react-native";
-import { createPaginationComponents } from "@/helpers/paginationHelpers";
+
+const PAGE_SIZE = PAGINATION_DEFAULT_TAKE;
+
+/**
+ * Render header dengan search input
+ */
+const renderHeader = (search: string, setSearch: (text: string) => void) => (
+
+ }
+ placeholder="Cari Pengguna"
+ borderRadius={50}
+ containerStyle={{ marginBottom: 0 }}
+ />
+);
+
+/**
+ * Render item user
+ */
+const renderItem = ({ item }: { item: any }) => (
+
+ {
+ router.push(`/profile/${item?.Profile?.id}`);
+ }}
+ >
+
+
+
+
+
+
+ {item?.username}
+ +{item?.nomor}
+ {item?.Profile?.businessField && (
+
+ {item?.Profile?.businessField}
+
+ )}
+
+
+
+
+
+
+
+
+);
export default function UserSearchMainView_V2() {
const isInitialMount = useRef(true);
const [search, setSearch] = useState("");
- const {
- listData,
- loading,
- refreshing,
- hasMore,
- onRefresh,
- loadMore,
- isInitialLoad,
- } = usePagination({
+ const pagination = usePagination({
fetchFunction: async (page, searchQuery) => {
const response = await apiAllUser({
page: String(page),
@@ -41,7 +110,7 @@ export default function UserSearchMainView_V2() {
});
return response;
},
- pageSize: PAGINATION_DEFAULT_TAKE,
+ pageSize: PAGE_SIZE,
searchQuery: search,
});
@@ -49,119 +118,42 @@ export default function UserSearchMainView_V2() {
useFocusEffect(
useCallback(() => {
if (isInitialMount.current) {
- // Skip saat pertama kali mount
isInitialMount.current = false;
return;
}
- // Hanya refresh saat kembali dari screen lain
- onRefresh();
- }, [onRefresh]),
- );
-
- const renderHeader = () => (
- <>
-
- }
- placeholder="Cari Pengguna"
- borderRadius={50}
- containerStyle={{ marginBottom: 0 }}
- />
- >
- );
-
- const renderItem = ({ item }: { item: any }) => (
-
- {
- console.log("Ke Profile");
- router.push(`/profile/${item?.Profile?.id}`);
- }}
- >
-
-
-
-
-
-
- {item?.username}
- +{item?.nomor}
- {item?.Profile?.businessField && (
-
- {item?.Profile?.businessField}
-
- )}
-
-
-
-
-
-
-
-
+ pagination.onRefresh();
+ }, [pagination.onRefresh]),
);
const { ListEmptyComponent, ListFooterComponent } =
createPaginationComponents({
- loading,
- refreshing,
- listData,
+ loading: pagination.loading,
+ refreshing: pagination.refreshing,
+ listData: pagination.listData,
searchQuery: search,
emptyMessage: "Tidak ada pengguna ditemukan",
emptySearchMessage: "Tidak ada hasil pencarian",
skeletonCount: PAGINATION_DEFAULT_TAKE,
skeletonHeight: 100,
loadingFooterText: "Memuat lebih banyak pengguna...",
- isInitialLoad,
+ isInitialLoad: pagination.isInitialLoad,
});
return (
- <>
-
- }
- ListFooterComponent={ListFooterComponent}
- ListEmptyComponent={ListEmptyComponent}
- />
- >
+
+ }
+ ListFooterComponent={ListFooterComponent}
+ ListEmptyComponent={ListEmptyComponent}
+ />
);
}
diff --git a/service/api-client/api-user.ts b/service/api-client/api-user.ts
index 8cd3155..f1ffab1 100644
--- a/service/api-client/api-user.ts
+++ b/service/api-client/api-user.ts
@@ -6,13 +6,13 @@ export async function apiUser(id: string) {
}
export async function apiAllUser({
- page,
+ page = "1",
search,
}: {
page?: string;
search?: string;
}) {
- const pageQuery = page ? `?page=${page}` : "";
+ const pageQuery = `?page=${page}`;
const searchQuery = search ? `&search=${search}` : "";
try {
diff --git a/styles/global-styles.ts b/styles/global-styles.ts
index 30f8781..efdd806 100644
--- a/styles/global-styles.ts
+++ b/styles/global-styles.ts
@@ -159,7 +159,7 @@ export const GStyles = StyleSheet.create({
transform: [{ scale: 1.05 }],
},
iconContainer: {
- padding: 8,
+ padding: 5,
borderRadius: 20,
// marginBottom: 4,
},
diff --git a/styles/tabs-styles.ts b/styles/tabs-styles.ts
index 70fe42b..4788d93 100644
--- a/styles/tabs-styles.ts
+++ b/styles/tabs-styles.ts
@@ -11,7 +11,7 @@ export const TabsStyles: BottomTabNavigationOptions = {
tabBarStyle: Platform.select({
ios: {
borderTopWidth: 0,
- paddingTop: 5,
+ paddingTop: 12,
height: OS_IOS_HEIGHT,
},
android: {