Invesment

Fix: create & edit list master sudah terintegrasi ke API

### No Issue
This commit is contained in:
2025-09-30 11:00:31 +08:00
parent ccdd7730b2
commit 3d8d8568a3
3 changed files with 279 additions and 126 deletions

View File

@@ -4,6 +4,7 @@ import {
ButtonCustom, ButtonCustom,
InformationBox, InformationBox,
LandscapeFrameUploaded, LandscapeFrameUploaded,
LoaderCustom,
SelectCustom, SelectCustom,
Spacing, Spacing,
StackCustom, StackCustom,
@@ -12,13 +13,11 @@ import {
} from "@/components"; } from "@/components";
import API_STRORAGE from "@/constants/base-url-api-strorage"; import API_STRORAGE from "@/constants/base-url-api-strorage";
import DIRECTORY_ID from "@/constants/directory-id"; import DIRECTORY_ID from "@/constants/directory-id";
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 { import {
apiInvestmentGetById, apiInvestmentGetById,
apiInvestmentUpdateData, apiInvestmentUpdateData,
} from "@/service/api-client/api-investment"; } from "@/service/api-client/api-investment";
import { apiMasterInvestment } from "@/service/api-client/api-master";
import { import {
deleteImageService, deleteImageService,
uploadImageService, uploadImageService,
@@ -26,6 +25,7 @@ import {
import { formatCurrencyDisplay } from "@/utils/formatCurrencyDisplay"; import { formatCurrencyDisplay } from "@/utils/formatCurrencyDisplay";
import pickFile from "@/utils/pickFile"; import pickFile from "@/utils/pickFile";
import { router, useFocusEffect, useLocalSearchParams } from "expo-router"; import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
import _ from "lodash";
import { useCallback, useState } from "react"; import { useCallback, useState } from "react";
import Toast from "react-native-toast-message"; import Toast from "react-native-toast-message";
@@ -61,24 +61,33 @@ export default function InvestmentEdit() {
const [image, setImage] = useState<string | null>(null); const [image, setImage] = useState<string | null>(null);
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const [loadingMaster, setLoadingMaster] = useState(false);
const displayTargetDana = formatCurrencyDisplay(data?.targetDana); const [listPencarianInvestor, setListPencarianInvestor] = useState<any[]>([]);
const displayHargaPerLembar = formatCurrencyDisplay(data?.hargaLembar); const [listPeriodeDeviden, setListPeriodeDeviden] = useState<any[]>([]);
const displayTotalLembar = formatCurrencyDisplay( const [listPembagianDeviden, setListPembagianDeviden] = useState<any[]>([]);
Number(data?.targetDana) / Number(data?.hargaLembar)
);
const handleChangeCurrency = (field: keyof typeof data) => (text: string) => {
const numeric = text.replace(/\D/g, "");
setData((prev) => ({ ...prev, [field]: numeric }));
};
useFocusEffect( useFocusEffect(
useCallback(() => { useCallback(() => {
onLoadMaster();
onLoadData(); onLoadData();
}, [id]) }, [id])
); );
const onLoadMaster = async () => {
try {
setLoadingMaster(true);
const response = await apiMasterInvestment({ category: "" });
setListPencarianInvestor(response.data.pencarianInvestor);
setListPeriodeDeviden(response.data.periodeDeviden);
setListPembagianDeviden(response.data.pembagianDeviden);
} catch (error) {
console.log("[ERROR]", error);
} finally {
setLoadingMaster(false);
}
};
const onLoadData = async () => { const onLoadData = async () => {
try { try {
const response = await apiInvestmentGetById({ const response = await apiInvestmentGetById({
@@ -91,25 +100,44 @@ export default function InvestmentEdit() {
} }
}; };
const handleSubmitUpdate = async () => { const displayTargetDana = formatCurrencyDisplay(data?.targetDana);
let newData = { const displayHargaPerLembar = formatCurrencyDisplay(data?.hargaLembar);
...data, const displayTotalLembar = formatCurrencyDisplay(
}; Number(data?.targetDana) / Number(data?.hargaLembar)
);
const handleChangeCurrency = (field: keyof typeof data) => (text: string) => {
const numeric = text.replace(/\D/g, "");
setData((prev) => ({ ...prev, [field]: numeric }));
};
const validateData = () => {
if ( if (
newData?.title === "" || !data.title ||
newData?.targetDana === "" || !data.targetDana ||
newData?.hargaLembar === "" || !data.hargaLembar ||
newData?.totalLembar === "" || !data.totalLembar ||
newData?.roi === "" || !data.roi ||
newData?.masterPencarianInvestorId === "" || !data.masterPencarianInvestorId ||
newData?.masterPeriodeDevidenId === "" || !data.masterPeriodeDevidenId ||
newData?.masterPembagianDevidenId === "" !data.masterPembagianDevidenId
) { ) {
Toast.show({ Toast.show({
type: "info", type: "info",
text1: "Harap isi semua data", text1: "Harap isi semua data",
}); });
return false;
}
return true;
};
const handleSubmitUpdate = async () => {
let newData = {
...data,
};
if (!validateData()) {
return; return;
} }
@@ -153,7 +181,10 @@ export default function InvestmentEdit() {
data: newData, data: newData,
}); });
console.log("[RESPONSE UPDATE]", JSON.parse(JSON.stringify(responseUpdate))); console.log(
"[RESPONSE UPDATE]",
JSON.parse(JSON.stringify(responseUpdate))
);
if (responseUpdate.success) { if (responseUpdate.success) {
Toast.show({ Toast.show({
@@ -249,47 +280,72 @@ export default function InvestmentEdit() {
value={data?.roi === "" ? "" : data?.roi} value={data?.roi === "" ? "" : data?.roi}
/> />
<SelectCustom {loadingMaster ? (
required <LoaderCustom />
placeholder="Pilih batas waktu" ) : (
label="Pencarian Investor" <SelectCustom
data={dummyListPencarianInvestor.map((item) => ({ required
label: item.name + `${" "}hari`, placeholder="Pilih batas waktu"
value: item.id, label="Pencarian Investor"
}))} data={
onChange={(value) => _.isEmpty(listPencarianInvestor)
setData({ ...data, masterPencarianInvestorId: value as any }) ? []
} : listPencarianInvestor.map((item) => ({
value={data.masterPencarianInvestorId} label: item.name + `${" "}hari`,
/> value: item.id,
}))
}
onChange={(value) =>
setData({ ...data, masterPencarianInvestorId: value as any })
}
value={data.masterPencarianInvestorId}
/>
)}
<SelectCustom {loadingMaster ? (
required <LoaderCustom />
placeholder="Pilih batas waktu" ) : (
label="Pilih Periode Deviden" <SelectCustom
data={dummyPeriodeDeviden.map((item) => ({ required
label: item.name, placeholder="Pilih batas waktu"
value: item.id, label="Pilih Periode Deviden"
}))} data={
onChange={(value) => _.isEmpty(listPeriodeDeviden)
setData({ ...data, masterPeriodeDevidenId: value as any }) ? []
} : listPeriodeDeviden.map((item) => ({
value={data.masterPeriodeDevidenId} label: item.name,
/> value: item.id,
}))
}
onChange={(value) =>
setData({ ...data, masterPeriodeDevidenId: value as any })
}
value={data.masterPeriodeDevidenId}
/>
)}
{loadingMaster ? (
<LoaderCustom />
) : (
<SelectCustom
required
placeholder="Pilih batas waktu"
label="Pilih Pembagian Deviden"
data={
_.isEmpty(listPembagianDeviden)
? []
: listPembagianDeviden.map((item) => ({
label: item.name + `${" "}bulan`,
value: item.id,
}))
}
onChange={(value) =>
setData({ ...data, masterPembagianDevidenId: value as any })
}
value={data.masterPembagianDevidenId}
/>
)}
<SelectCustom
required
placeholder="Pilih batas waktu"
label="Pilih Pembagian Deviden"
data={dummyPembagianDeviden.map((item) => ({
label: item.name + `${" "}bulan`,
value: item.id,
}))}
onChange={(value) =>
setData({ ...data, masterPembagianDevidenId: value as any })
}
value={data.masterPembagianDevidenId}
/>
<Spacing /> <Spacing />
<ButtonCustom isLoading={isLoading} onPress={handleSubmitUpdate}> <ButtonCustom isLoading={isLoading} onPress={handleSubmitUpdate}>
Simpan Simpan

View File

@@ -5,6 +5,7 @@ import {
CenterCustom, CenterCustom,
InformationBox, InformationBox,
LandscapeFrameUploaded, LandscapeFrameUploaded,
LoaderCustom,
SelectCustom, SelectCustom,
Spacing, Spacing,
StackCustom, StackCustom,
@@ -15,16 +16,15 @@ import {
import { MainColor } from "@/constants/color-palet"; import { MainColor } from "@/constants/color-palet";
import DIRECTORY_ID from "@/constants/directory-id"; import DIRECTORY_ID from "@/constants/directory-id";
import { useAuth } from "@/hooks/use-auth"; import { useAuth } from "@/hooks/use-auth";
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 { apiInvestmentCreate } from "@/service/api-client/api-investment"; import { apiInvestmentCreate } from "@/service/api-client/api-investment";
import { apiMasterInvestment } from "@/service/api-client/api-master";
import { uploadImageService } from "@/service/upload-service"; import { uploadImageService } from "@/service/upload-service";
import { formatCurrencyDisplay } from "@/utils/formatCurrencyDisplay"; import { formatCurrencyDisplay } from "@/utils/formatCurrencyDisplay";
import pickFile, { IFileData } from "@/utils/pickFile"; import pickFile, { IFileData } from "@/utils/pickFile";
import { FontAwesome5 } from "@expo/vector-icons"; import { FontAwesome5 } from "@expo/vector-icons";
import { router } from "expo-router"; import { router, useFocusEffect } from "expo-router";
import { useState } from "react"; import _ from "lodash";
import { useCallback, useState } from "react";
import Toast from "react-native-toast-message"; import Toast from "react-native-toast-message";
export default function InvestmentCreate() { export default function InvestmentCreate() {
@@ -46,6 +46,32 @@ export default function InvestmentCreate() {
const [pdf, setPdf] = useState<IFileData | null>(null); const [pdf, setPdf] = useState<IFileData | null>(null);
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const [loadingMaster, setLoadingMaster] = useState(false);
const [listPencarianInvestor, setListPencarianInvestor] = useState<any[]>([]);
const [listPeriodeDeviden, setListPeriodeDeviden] = useState<any[]>([]);
const [listPembagianDeviden, setListPembagianDeviden] = useState<any[]>([]);
useFocusEffect(
useCallback(() => {
onLoadMaster();
}, [])
);
const onLoadMaster = async () => {
try {
setLoadingMaster(true);
const response = await apiMasterInvestment({ category: "" });
setListPencarianInvestor(response.data.pencarianInvestor);
setListPeriodeDeviden(response.data.periodeDeviden);
setListPembagianDeviden(response.data.pembagianDeviden);
} catch (error) {
console.log("[ERROR]", error);
} finally {
setLoadingMaster(false);
}
};
const displayTargetDana = formatCurrencyDisplay(data.targetDana); const displayTargetDana = formatCurrencyDisplay(data.targetDana);
const displayHargaPerLembar = formatCurrencyDisplay(data.hargaPerLembar); const displayHargaPerLembar = formatCurrencyDisplay(data.hargaPerLembar);
const displayTotalLembar = formatCurrencyDisplay( const displayTotalLembar = formatCurrencyDisplay(
@@ -57,15 +83,7 @@ export default function InvestmentCreate() {
setData((prev) => ({ ...prev, [field]: numeric })); setData((prev) => ({ ...prev, [field]: numeric }));
}; };
const handleSubmit = async () => { const validateData = () => {
if (!image || !pdf) {
Toast.show({
type: "error",
text1: "Harap pilih gambar dan file PDF",
});
return;
}
if ( if (
!data.title || !data.title ||
!data.targetDana || !data.targetDana ||
@@ -79,6 +97,22 @@ export default function InvestmentCreate() {
type: "error", type: "error",
text1: "Harap isi semua data", text1: "Harap isi semua data",
}); });
return false;
}
return true;
};
const handleSubmit = async () => {
if (!validateData()) {
return;
}
if (!image || !pdf) {
Toast.show({
type: "error",
text1: "Harap upload gambar dan file PDF",
});
return; return;
} }
@@ -258,47 +292,72 @@ export default function InvestmentCreate() {
} }
/> />
<SelectCustom {loadingMaster ? (
required <LoaderCustom />
placeholder="Pilih batas waktu" ) : (
label="Pencarian Investor" <SelectCustom
data={dummyListPencarianInvestor.map((item) => ({ required
label: item.name + `${" "}hari`, placeholder="Pilih batas waktu"
value: item.id, label="Pencarian Investor"
}))} data={
onChange={(value) => _.isEmpty(listPencarianInvestor)
setData({ ...data, pencarianInvestor: value as any }) ? []
} : listPencarianInvestor.map((item) => ({
value={data.pencarianInvestor} label: item.name + `${" "}hari`,
/> value: item.id,
}))
}
onChange={(value) =>
setData({ ...data, pencarianInvestor: value as any })
}
value={data.pencarianInvestor}
/>
)}
<SelectCustom {loadingMaster ? (
required <LoaderCustom />
placeholder="Pilih batas waktu" ) : (
label="Pilih Periode Deviden" <SelectCustom
data={dummyPeriodeDeviden.map((item) => ({ required
label: item.name, placeholder="Pilih batas waktu"
value: item.id, label="Pilih Periode Deviden"
}))} data={
onChange={(value) => _.isEmpty(listPeriodeDeviden)
setData({ ...data, periodeDeviden: value as any }) ? []
} : listPeriodeDeviden.map((item) => ({
value={data.periodeDeviden} label: item.name,
/> value: item.id,
}))
}
onChange={(value) =>
setData({ ...data, periodeDeviden: value as any })
}
value={data.periodeDeviden}
/>
)}
{loadingMaster ? (
<LoaderCustom />
) : (
<SelectCustom
required
placeholder="Pilih batas waktu"
label="Pilih Pembagian Deviden"
data={
_.isEmpty(listPembagianDeviden)
? []
: listPembagianDeviden.map((item) => ({
label: item.name + `${" "}bulan`,
value: item.id,
}))
}
onChange={(value) =>
setData({ ...data, pembagianDeviden: value as any })
}
value={data.pembagianDeviden}
/>
)}
<SelectCustom
required
placeholder="Pilih batas waktu"
label="Pilih Pembagian Deviden"
data={dummyPembagianDeviden.map((item) => ({
label: item.name + `${" "}bulan`,
value: item.id,
}))}
onChange={(value) =>
setData({ ...data, pembagianDeviden: value as any })
}
value={data.pembagianDeviden}
/>
<Spacing /> <Spacing />
<ButtonCustom isLoading={isLoading} onPress={() => handleSubmit()}> <ButtonCustom isLoading={isLoading} onPress={() => handleSubmit()}>
Simpan Simpan

View File

@@ -1,5 +1,6 @@
import { apiConfig } from "../api-config"; import { apiConfig } from "../api-config";
// ================== START MASTER PORTFOLIO ================== //
export async function apiMasterBidangBisnis() { export async function apiMasterBidangBisnis() {
try { try {
const response = await apiConfig.get(`/master/bidang-bisnis`); const response = await apiConfig.get(`/master/bidang-bisnis`);
@@ -21,6 +22,10 @@ export async function apiMasterSubBidangBisnis({ id }: { id?: string }) {
} }
} }
// ================== END MASTER PORTFOLIO ================== //
// ================== START MASTER EVENT ================== //
export async function apiMasterEventType() { export async function apiMasterEventType() {
try { try {
const response = await apiConfig.get(`/mobile/master/event-type`); const response = await apiConfig.get(`/mobile/master/event-type`);
@@ -30,6 +35,10 @@ export async function apiMasterEventType() {
} }
} }
// ================== END MASTER EVENT ================== //
// ================== START MASTER COLLABORATION ================== //
export async function apiMasterCollaborationType() { export async function apiMasterCollaborationType() {
try { try {
const response = await apiConfig.get( const response = await apiConfig.get(
@@ -41,6 +50,10 @@ export async function apiMasterCollaborationType() {
} }
} }
// ================== END MASTER COLLABORATION ================== //
// ================== START MASTER FORUM ================== //
export async function apiMasterForumReportList() { export async function apiMasterForumReportList() {
try { try {
const response = await apiConfig.get(`/mobile/master/forum-report`); const response = await apiConfig.get(`/mobile/master/forum-report`);
@@ -50,6 +63,8 @@ export async function apiMasterForumReportList() {
} }
} }
// ================== END MASTER FORUM ================== //
export async function apiForumCreateReportPosting({ export async function apiForumCreateReportPosting({
id, id,
data, data,
@@ -58,9 +73,12 @@ export async function apiForumCreateReportPosting({
data: any; data: any;
}) { }) {
try { try {
const response = await apiConfig.post(`/mobile/forum/${id}/report-posting`, { const response = await apiConfig.post(
data: data, `/mobile/forum/${id}/report-posting`,
}); {
data: data,
}
);
return response.data; return response.data;
} catch (error) { } catch (error) {
throw error; throw error;
@@ -75,12 +93,32 @@ export async function apiForumCreateReportCommentar({
data: any; data: any;
}) { }) {
try { try {
const response = await apiConfig.post(`/mobile/forum/${id}/report-commentar`, { const response = await apiConfig.post(
data: data, `/mobile/forum/${id}/report-commentar`,
}); {
data: data,
}
);
return response.data;
} catch (error) {
throw error;
}
}
// ================== START MASTER INVESTMENT ================== //
export async function apiMasterInvestment({
category,
}: {
category?: "pencarian-investor" | "periode-deviden" | "pembagian-deviden" | string;
}) {
const selectCategory = category ? `?category=${category}` : "";
try {
const response = await apiConfig.get(
`/mobile/master/investment${selectCategory}`
);
return response.data; return response.data;
} catch (error) { } catch (error) {
throw error; throw error;
} }
} }