diff --git a/app/(application)/(user)/_layout.tsx b/app/(application)/(user)/_layout.tsx index 80e1242..431adff 100644 --- a/app/(application)/(user)/_layout.tsx +++ b/app/(application)/(user)/_layout.tsx @@ -193,6 +193,13 @@ export default function UserLayout() { {/* ========== End Crowdfunding Section ========= */} {/* ========== Investment Section ========= */} + , + }} + /> {/* ========== End Investment Section ========= */} - + {/* ========== Donation Section ========= */} + ( + + ), + }} + /> + ( + + ), + }} + /> + ( + + ), + }} + /> + ( + + ), + }} + /> + + ); +} diff --git a/app/(application)/(user)/investment/(tabs)/index.tsx b/app/(application)/(user)/investment/(tabs)/index.tsx new file mode 100644 index 0000000..060e8fe --- /dev/null +++ b/app/(application)/(user)/investment/(tabs)/index.tsx @@ -0,0 +1,81 @@ +import { + BaseBox, + FloatingButton, + Grid, + ProgressCustom, + StackCustom, + TextCustom, + ViewWrapper, +} from "@/components"; +import DUMMY_IMAGE from "@/constants/dummy-image-value"; +import dayjs from "dayjs"; +import { Image } from "expo-image"; +import { router } from "expo-router"; +import { View } from "react-native"; + +export default function InvestmentBursa() { + return ( + router.push("/investment/create")} /> + } + > + {Array.from({ length: 10 }).map((_, index) => ( + + + + + + + + + + + + Title here : Lorem ipsum dolor sit amet consectetur + adipisicing elit. Omnis, exercitationem, sequi enim quod + distinctio maiores laudantium amet, quidem atque repellat sit + vitae qui aliquam est veritatis laborum eum voluptatum totam! + + + + Sisa waktu: {dayjs().diff(dayjs(), "day")} hari + + + + + + ))} + + ); +} + + +// +// Progress 70% +// + +// Success Progress +// + +// Warning Progress (small) +// + +// Error Indeterminate +// + +// Custom Radius +// + +// + +// + +// + +// +// ; \ No newline at end of file diff --git a/app/(application)/(user)/investment/(tabs)/my-holding.tsx b/app/(application)/(user)/investment/(tabs)/my-holding.tsx new file mode 100644 index 0000000..7937ec4 --- /dev/null +++ b/app/(application)/(user)/investment/(tabs)/my-holding.tsx @@ -0,0 +1,11 @@ +import { ViewWrapper, TextCustom } from "@/components"; + +export default function InvestmentMyHolding() { + return ( + + + My Holding + + + ); +} diff --git a/app/(application)/(user)/investment/(tabs)/portofolio.tsx b/app/(application)/(user)/investment/(tabs)/portofolio.tsx new file mode 100644 index 0000000..a09b2aa --- /dev/null +++ b/app/(application)/(user)/investment/(tabs)/portofolio.tsx @@ -0,0 +1,11 @@ +import { ViewWrapper, TextCustom } from "@/components"; + +export default function InvestmentPortofolio() { + return ( + + + Portofolio + + + ); +} diff --git a/app/(application)/(user)/investment/(tabs)/transaction.tsx b/app/(application)/(user)/investment/(tabs)/transaction.tsx new file mode 100644 index 0000000..a2cc7a0 --- /dev/null +++ b/app/(application)/(user)/investment/(tabs)/transaction.tsx @@ -0,0 +1,11 @@ +import { ViewWrapper, TextCustom } from "@/components"; + +export default function InvestmentTransaction() { + return ( + + + Transaction + + + ); +} diff --git a/app/(application)/(user)/investment/create.tsx b/app/(application)/(user)/investment/create.tsx index 9078b78..c9450cc 100644 --- a/app/(application)/(user)/investment/create.tsx +++ b/app/(application)/(user)/investment/create.tsx @@ -1,11 +1,197 @@ -import { TextCustom, ViewWrapper } from "@/components"; +import { + BaseBox, + ButtonCenteredOnly, + ButtonCustom, + CenterCustom, + InformationBox, + LandscapeFrameUploaded, + SelectCustom, + Spacing, + StackCustom, + TextInputCustom, + ViewWrapper, +} from "@/components"; +import { MainColor } from "@/constants/color-palet"; +import dummyPembagianDeviden from "@/lib/dummy-data/investment/pembagian-deviden"; +import dummyListPencarianInvestor from "@/lib/dummy-data/investment/pencarian-investor"; +import dummyPeriodeDeviden from "@/lib/dummy-data/investment/periode-deviden"; +import { FontAwesome5 } from "@expo/vector-icons"; +import { router } from "expo-router"; +import { useState } from "react"; export default function InvestmentCreate() { + const [data, setData] = useState({ + title: "", + targetDana: 0, + hargaPerLembar: 0, + totalLembar: 0, + rasioKeuntungan: 0, + pencarianInvestor: "", + periodeDeviden: "", + pembagianDeviden: "", + }); + +// const [coba, setCoba] = useState(""); return ( - - Buat Investasi - + + {/* + setCoba(value)} + value={coba} + keyboardType="decimal-pad" + /> + */} + + + + router.push("/take-picture/1")} + > + Upload + + + + + + + + + + + + router.push("/take-picture/1")} + > + Upload File + + + + setData({ ...data, title: value })} + /> + + + setData({ ...data, targetDana: Number(value) }) + } + value={data.targetDana === 0 ? "" : data.targetDana.toString()} + /> + + + setData({ ...data, targetDana: Number(value) }) + } + value={data.targetDana === 0 ? "" : data.targetDana.toString()} + /> + + + setData({ ...data, targetDana: Number(value) }) + } + value={data.targetDana === 0 ? "" : data.targetDana.toString()} + /> + + + setData({ ...data, totalLembar: Number(value) }) + } + value={data.totalLembar === 0 ? "" : data.totalLembar.toString()} + /> + + + setData({ ...data, rasioKeuntungan: Number(value) }) + } + value={ + data.rasioKeuntungan === 0 ? "" : data.rasioKeuntungan.toString() + } + /> + + ({ + label: item.name + `${" "}hari`, + value: item.id, + }))} + onChange={(value) => + setData({ ...data, pencarianInvestor: value as any }) + } + value={data.pencarianInvestor} + /> + + ({ + label: item.name, + value: item.id, + }))} + onChange={(value) => + setData({ ...data, periodeDeviden: value as any }) + } + value={data.periodeDeviden} + /> + + ({ + label: item.name + `${" "}bulan`, + value: item.id, + }))} + onChange={(value) => + setData({ ...data, pembagianDeviden: value as any }) + } + value={data.pembagianDeviden} + /> + + router.replace("/investment/portofolio")}> + Simpan + + + ); } diff --git a/components/Progress/ProgressCustom.tsx b/components/Progress/ProgressCustom.tsx new file mode 100644 index 0000000..dc8a20a --- /dev/null +++ b/components/Progress/ProgressCustom.tsx @@ -0,0 +1,193 @@ +import { useTheme } from "@react-navigation/native"; +import React from "react"; +import { Animated, StyleSheet, Text, View, ViewStyle } from "react-native"; + +type ProgressColor = + | "primary" + | "success" + | "warning" + | "error" + | "info" + | "dark"; + +type ProgressSize = "xs" | "sm" | "md" | "lg" | "xl"; + +interface ProgressProps { + value?: number | null; + color?: ProgressColor; + size?: ProgressSize; + radius?: number; + style?: ViewStyle; + animated?: boolean; + label?: React.ReactNode; // Konten label (bisa string, number, atau elemen) + showLabel?: boolean; // Jika ingin mengontrol visibilitas +} + +const getColor = (color: ProgressColor, isDark: boolean) => { + const palette: Record = { + primary: "#FFC107", + success: "#228B22", + warning: "#FFA500", + error: "#DC3545", + info: "#177DDC", + dark: isDark ? "#DADADA" : "#212121", + }; + return palette[color]; +}; + +const getSize = (size: ProgressSize): number => { + const sizes: Record = { + xs: 6, + sm: 8, + md: 12, + lg: 16, + xl: 20, + }; + return sizes[size]; +}; + +const ProgressCustom: React.FC = ({ + value = 0, + color = "primary", + size = "md", + radius = 999, + style, + animated = true, + label, + showLabel = true, +}) => { + const { dark } = useTheme(); + const isDark = dark ?? false; + + const barHeight = getSize(size); + const progressColor = getColor(color, isDark); + const displayValue = + typeof value === "number" ? Math.max(0, Math.min(100, value)) : 0; + + // Animasi indeterminate + const translateX = React.useRef(new Animated.Value(-1)).current; + + React.useEffect(() => { + if (value === null && animated) { + const animation = Animated.loop( + Animated.timing(translateX, { + toValue: 1, + duration: 1200, + useNativeDriver: true, + }) + ); + animation.start(); + return () => animation.stop(); + } + }, [value, animated, translateX]); + + const isIndeterminate = value === null; + + // Tentukan teks label + const labelText = + label !== undefined + ? label + : typeof value === "number" + ? `${Math.round(value)}%` + : ""; + + return ( + + {/* Progress Fill */} + {isIndeterminate ? ( + + ) : ( + + )} + + {/* Label di tengah */} + {showLabel && labelText ? ( + + + {labelText} + + + ) : null} + + ); +}; + +export default ProgressCustom; + +const styles = StyleSheet.create({ + container: { + overflow: "hidden", + backgroundColor: "rgba(0,0,0,0.1)", + width: "100%", + justifyContent: "center", // Pusatkan label secara vertikal + }, + progressBar: { + backgroundColor: "#007BFF", + }, + indeterminateBar: { + position: "absolute", + top: 0, + left: 0, + backgroundColor: "#007BFF", + }, + label: { + textAlign: "center", + width: "100%", + // Hindari overlap dengan background — bisa tambahkan shadow atau background jika perlu + textShadowColor: "rgba(255,255,255,0.6)", + textShadowOffset: { width: 1, height: 1 }, + textShadowRadius: 1, + }, +}); diff --git a/components/index.ts b/components/index.ts index 41cd990..207a212 100644 --- a/components/index.ts +++ b/components/index.ts @@ -55,6 +55,8 @@ import TabBarBackground from "./_ShareComponent/TabBarBackground"; import ViewWrapper from "./_ShareComponent/ViewWrapper"; import SearchInput from "./_ShareComponent/SearchInput"; import DummyLandscapeImage from "./_ShareComponent/DummyLandscapeImage"; +// Progress +import ProgressCustom from "./Progress/ProgressCustom"; export { AlertCustom, @@ -96,6 +98,8 @@ export { // Map MapCustom, MenuDrawerDynamicGrid, + // Progress + ProgressCustom, // Scroll ScrollableCustom, // Select diff --git a/lib/dummy-data/investment/pembagian-deviden.ts b/lib/dummy-data/investment/pembagian-deviden.ts new file mode 100644 index 0000000..3f6909b --- /dev/null +++ b/lib/dummy-data/investment/pembagian-deviden.ts @@ -0,0 +1,20 @@ +const dummyPembagianDeviden = [ + { + id: "1", + name: "3", + }, + { + id: "2", + name: "6", + }, + { + id: "3", + name: "9", + }, + { + id: "4", + name: "12", + }, +]; + +export default dummyPembagianDeviden; diff --git a/lib/dummy-data/investment/pencarian-investor.ts b/lib/dummy-data/investment/pencarian-investor.ts new file mode 100644 index 0000000..696ca02 --- /dev/null +++ b/lib/dummy-data/investment/pencarian-investor.ts @@ -0,0 +1,20 @@ +const dummyListPencarianInvestor = [ + { + id: "1", + name: "30", + }, + { + id: "2", + name: "60", + }, + { + id: "3", + name: "90", + }, + { + id: "4", + name: "120", + }, +]; + +export default dummyListPencarianInvestor; \ No newline at end of file diff --git a/lib/dummy-data/investment/periode-deviden.ts b/lib/dummy-data/investment/periode-deviden.ts new file mode 100644 index 0000000..ba5bf94 --- /dev/null +++ b/lib/dummy-data/investment/periode-deviden.ts @@ -0,0 +1,12 @@ +const dummyPeriodeDeviden = [ + { + id: "1", + name: "Selamanya", + }, + { + id: "2", + name: "Satu tahun", + }, +]; + +export default dummyPeriodeDeviden;