Compare commits
4 Commits
api-invest
...
api-invest
| Author | SHA1 | Date | |
|---|---|---|---|
| 2be4afdcb1 | |||
| aa85e05f79 | |||
| c2acb97a37 | |||
| 250b216a54 |
@@ -2,18 +2,46 @@ import {
|
||||
BaseBox,
|
||||
FloatingButton,
|
||||
Grid,
|
||||
LoaderCustom,
|
||||
ProgressCustom,
|
||||
StackCustom,
|
||||
TextCustom,
|
||||
ViewWrapper,
|
||||
} from "@/components";
|
||||
import API_STRORAGE from "@/constants/base-url-api-strorage";
|
||||
import DUMMY_IMAGE from "@/constants/dummy-image-value";
|
||||
import { apiInvestmentGetAll } from "@/service/api-client/api-investment";
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
import dayjs from "dayjs";
|
||||
import { Image } from "expo-image";
|
||||
import { router } from "expo-router";
|
||||
import { router, useFocusEffect } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import { useCallback, useState } from "react";
|
||||
import { View } from "react-native";
|
||||
|
||||
export default function InvestmentBursa() {
|
||||
const [list, setList] = useState<any[] | null>(null);
|
||||
const [loadingList, setLoadingList] = useState(false);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadList();
|
||||
}, [])
|
||||
);
|
||||
|
||||
const onLoadList = async () => {
|
||||
try {
|
||||
setLoadingList(true);
|
||||
const response = await apiInvestmentGetAll();
|
||||
console.log("[DATA LIST]", JSON.stringify(response.data, null, 2));
|
||||
setList(response.data);
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
setLoadingList(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<ViewWrapper
|
||||
hideFooter
|
||||
@@ -21,40 +49,77 @@ export default function InvestmentBursa() {
|
||||
<FloatingButton onPress={() => router.push("/investment/create")} />
|
||||
}
|
||||
>
|
||||
{Array.from({ length: 10 }).map((_, index) => (
|
||||
<BaseBox key={index} paddingTop={7} paddingBottom={7} href={`/investment/${index}`}>
|
||||
<Grid>
|
||||
<Grid.Col span={5}>
|
||||
<Image
|
||||
source={DUMMY_IMAGE.background}
|
||||
style={{ width: "auto", height: 100, borderRadius: 10 }}
|
||||
/>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={1}>
|
||||
<View />
|
||||
</Grid.Col>
|
||||
<Grid.Col span={6}>
|
||||
<StackCustom>
|
||||
<TextCustom truncate={2}>
|
||||
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!
|
||||
</TextCustom>
|
||||
<ProgressCustom value={index % 5 * 20} size="lg" />
|
||||
<TextCustom>
|
||||
Sisa waktu: {dayjs().diff(dayjs(), "day")} hari
|
||||
</TextCustom>
|
||||
</StackCustom>
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
</BaseBox>
|
||||
))}
|
||||
{loadingList ? (
|
||||
<LoaderCustom />
|
||||
) : _.isEmpty(list) ? (
|
||||
<TextCustom>Belum ada data</TextCustom>
|
||||
) : (
|
||||
list?.map((item: any, index: number) => (
|
||||
<BaseBox
|
||||
key={index}
|
||||
paddingTop={7}
|
||||
paddingBottom={7}
|
||||
href={`/investment/${item.id}`}
|
||||
>
|
||||
<Grid>
|
||||
<Grid.Col span={5}>
|
||||
<Image
|
||||
source={
|
||||
item && item.imageId
|
||||
? API_STRORAGE.GET({ fileId: item.imageId })
|
||||
: DUMMY_IMAGE.background
|
||||
}
|
||||
style={{ width: "auto", height: 100, borderRadius: 10 }}
|
||||
/>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={1}>
|
||||
<View />
|
||||
</Grid.Col>
|
||||
<Grid.Col span={6}>
|
||||
<StackCustom>
|
||||
<TextCustom truncate={2}>{item.title}</TextCustom>
|
||||
<ProgressCustom
|
||||
label={`${item.progress}%`}
|
||||
value={item.progress}
|
||||
size="lg"
|
||||
/>
|
||||
{Number(item?.pencarianInvestor) -
|
||||
dayjs().diff(dayjs(item.countDown), "days") <=
|
||||
0 ? (
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
gap: 5,
|
||||
}}
|
||||
>
|
||||
<Ionicons
|
||||
name="alert-circle-outline"
|
||||
size={16}
|
||||
color="red"
|
||||
/>
|
||||
<TextCustom color="red" size="small">
|
||||
Periode Investasi Selesai
|
||||
</TextCustom>
|
||||
</View>
|
||||
) : (
|
||||
<TextCustom>
|
||||
Sisa waktu:{" "}
|
||||
{Number(item?.pencarianInvestor) -
|
||||
dayjs().diff(dayjs(item.countDown), "days")}{" "}
|
||||
hari
|
||||
</TextCustom>
|
||||
)}
|
||||
</StackCustom>
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
</BaseBox>
|
||||
))
|
||||
)}
|
||||
</ViewWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// <View style={{ padding: 20, gap: 16 }}>
|
||||
// <TextCustom>Progress 70%</TextCustom>
|
||||
// <ProgressCustom value={70} color="primary" size="md" />
|
||||
@@ -78,4 +143,4 @@ export default function InvestmentBursa() {
|
||||
// <ProgressCustom value={90} color="warning" size="lg" showLabel={false} />
|
||||
|
||||
// <ProgressCustom value={null} color="error" size="sm" label="Loading..." />
|
||||
// </View>;
|
||||
// </View>;
|
||||
|
||||
@@ -1,81 +1,123 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import {
|
||||
BadgeCustom,
|
||||
BaseBox,
|
||||
Grid,
|
||||
LoaderCustom,
|
||||
StackCustom,
|
||||
TextCustom,
|
||||
ViewWrapper,
|
||||
} from "@/components";
|
||||
import { dummyMasterStatusTransaction } from "@/lib/dummy-data/_master/status-transaction";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import { apiInvestmentGetInvoice } from "@/service/api-client/api-investment";
|
||||
import { GStyles } from "@/styles/global-styles";
|
||||
import dayjs from "dayjs";
|
||||
import { router } from "expo-router";
|
||||
import { formatChatTime } from "@/utils/formatChatTime";
|
||||
import { formatCurrencyDisplay } from "@/utils/formatCurrencyDisplay";
|
||||
import { router, useFocusEffect } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import { useCallback, useState } from "react";
|
||||
import { View } from "react-native";
|
||||
|
||||
export default function InvestmentTransaction() {
|
||||
const randomStatusData = Array.from({ length: 10 }, () => {
|
||||
const randomIndex = Math.floor(
|
||||
Math.random() * dummyMasterStatusTransaction.length
|
||||
);
|
||||
return dummyMasterStatusTransaction[randomIndex];
|
||||
});
|
||||
const { user } = useAuth();
|
||||
const [list, setList] = useState<any>([]);
|
||||
const [loadList, setLoadList] = useState<boolean>(false);
|
||||
|
||||
const handlePress = (value: string) => {
|
||||
if (value === "menunggu") {
|
||||
router.push(`/investment/${value}/(transaction-flow)/invoice`);
|
||||
} else if (value === "proses") {
|
||||
router.push(`/investment/${value}/(transaction-flow)/process`);
|
||||
} else if (value === "berhasil") {
|
||||
router.push(`/investment/${value}/(transaction-flow)/success`);
|
||||
} else if (value === "gagal") {
|
||||
router.push(`/investment/${value}/(transaction-flow)/failed`);
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadList();
|
||||
}, [user?.id])
|
||||
);
|
||||
|
||||
const onLoadList = async () => {
|
||||
try {
|
||||
setLoadList(true);
|
||||
const response = await apiInvestmentGetInvoice({
|
||||
authorId: user?.id as string,
|
||||
category: "transaction",
|
||||
});
|
||||
console.log("[RESPONSE LIST]", JSON.stringify(response.data, null, 2));
|
||||
setList(response.data);
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
setLoadList(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handlerColor = (status: string) => {
|
||||
if (status === "menunggu") {
|
||||
return "orange";
|
||||
} else if (status === "proses") {
|
||||
return "white";
|
||||
} else if (status === "berhasil") {
|
||||
return "green";
|
||||
} else if (status === "gagal") {
|
||||
return "red";
|
||||
}
|
||||
};
|
||||
|
||||
const handlePress = ({ id, status }: { id: string; status: string }) => {
|
||||
if (status === "menunggu") {
|
||||
router.push(`/investment/${id}/(transaction-flow)/invoice`);
|
||||
} else if (status === "proses") {
|
||||
router.push(`/investment/${id}/(transaction-flow)/process`);
|
||||
} else if (status === "berhasil") {
|
||||
router.push(`/investment/${id}/(transaction-flow)/success`);
|
||||
} else if (status === "gagal") {
|
||||
router.push(`/investment/${id}/(transaction-flow)/failed`);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<ViewWrapper hideFooter>
|
||||
{randomStatusData.map((item, i) => (
|
||||
<BaseBox
|
||||
key={i}
|
||||
paddingTop={7}
|
||||
paddingBottom={7}
|
||||
onPress={() => {
|
||||
handlePress(item.value);
|
||||
}}
|
||||
>
|
||||
<Grid>
|
||||
<Grid.Col span={6}>
|
||||
<StackCustom gap={"xs"}>
|
||||
<TextCustom truncate>
|
||||
Title Investment: Lorem ipsum dolor sit amet consectetur
|
||||
adipisicing elit. Am culpa excepturi deleniti soluta animi
|
||||
porro amet ducimus.
|
||||
</TextCustom>
|
||||
<TextCustom color="gray" size="small">
|
||||
{dayjs().format("DD/MM/YYYY")}
|
||||
</TextCustom>
|
||||
</StackCustom>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={1}>
|
||||
<View />
|
||||
</Grid.Col>
|
||||
<Grid.Col span={5} style={{ alignItems: "flex-end" }}>
|
||||
<StackCustom gap={"xs"}>
|
||||
<TextCustom bold truncate>
|
||||
Rp. 7.500.000
|
||||
</TextCustom>
|
||||
<BadgeCustom
|
||||
variant="light"
|
||||
color={item.color}
|
||||
style={GStyles.alignSelfFlexEnd}
|
||||
>
|
||||
{item.label}
|
||||
</BadgeCustom>
|
||||
</StackCustom>
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
</BaseBox>
|
||||
))}
|
||||
{loadList ? (
|
||||
<LoaderCustom />
|
||||
) : _.isEmpty(list) ? (
|
||||
<TextCustom>Tidak ada data</TextCustom>
|
||||
) : (
|
||||
list.map((item: any, i: number) => (
|
||||
<BaseBox
|
||||
key={i}
|
||||
paddingTop={7}
|
||||
paddingBottom={7}
|
||||
onPress={() => {
|
||||
handlePress({
|
||||
id: item.id,
|
||||
status: _.lowerCase(item.statusInvoice),
|
||||
});
|
||||
}}
|
||||
>
|
||||
<Grid>
|
||||
<Grid.Col span={6}>
|
||||
<StackCustom gap={"xs"}>
|
||||
<TextCustom truncate>{item?.title || "-"}</TextCustom>
|
||||
<TextCustom color="gray" size="small">
|
||||
{formatChatTime(item?.createdAt)}
|
||||
</TextCustom>
|
||||
</StackCustom>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={1}>
|
||||
<View />
|
||||
</Grid.Col>
|
||||
<Grid.Col span={5} style={{ alignItems: "flex-end" }}>
|
||||
<StackCustom gap={"xs"}>
|
||||
<TextCustom bold truncate>
|
||||
Rp. {formatCurrencyDisplay(item?.nominal) || "-"}
|
||||
</TextCustom>
|
||||
<BadgeCustom
|
||||
variant="light"
|
||||
color={handlerColor(_.lowerCase(item.statusInvoice))}
|
||||
style={GStyles.alignSelfFlexEnd}
|
||||
>
|
||||
{item?.statusInvoice || "-"}
|
||||
</BadgeCustom>
|
||||
</StackCustom>
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
</BaseBox>
|
||||
))
|
||||
)}
|
||||
</ViewWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,17 +7,78 @@ import {
|
||||
InformationBox,
|
||||
Spacing,
|
||||
StackCustom,
|
||||
TextCustom,
|
||||
TextInputCustom,
|
||||
ViewWrapper
|
||||
ViewWrapper,
|
||||
} from "@/components";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import DIRECTORY_ID from "@/constants/directory-id";
|
||||
import { apiInvestmentUpsertDocument } from "@/service/api-client/api-investment";
|
||||
import { uploadFileService } from "@/service/upload-service";
|
||||
import pickFile from "@/utils/pickFile";
|
||||
import { FontAwesome5 } from "@expo/vector-icons";
|
||||
import { router } from "expo-router";
|
||||
import { router, useLocalSearchParams } from "expo-router";
|
||||
import { useState } from "react";
|
||||
import Toast from "react-native-toast-message";
|
||||
|
||||
export default function InvestmentAddDocument() {
|
||||
const { id } = useLocalSearchParams();
|
||||
const [data, setData] = useState({
|
||||
title: "",
|
||||
});
|
||||
const [pdf, setPdf] = useState<any>(null);
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
|
||||
const handlerSubmit = async () => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const responseUploadFile = await uploadFileService({
|
||||
dirId: DIRECTORY_ID.investasi_dokumen,
|
||||
imageUri: pdf.uri,
|
||||
});
|
||||
|
||||
if (!responseUploadFile.success) {
|
||||
throw new Error(responseUploadFile.message);
|
||||
}
|
||||
|
||||
const newData = {
|
||||
title: data.title,
|
||||
fileId: responseUploadFile.data.id,
|
||||
};
|
||||
|
||||
const response = await apiInvestmentUpsertDocument({
|
||||
id: id as string,
|
||||
data: newData,
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: "Data berhasil disimpan",
|
||||
});
|
||||
|
||||
router.back();
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: "Gagal menyimpan data",
|
||||
});
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const buttonFooter = (
|
||||
<BoxButtonOnFooter>
|
||||
<ButtonCustom onPress={() => router.back()}>Simpan</ButtonCustom>
|
||||
<ButtonCustom
|
||||
isLoading={isLoading}
|
||||
disabled={!pdf || data.title.length <= 0}
|
||||
onPress={handlerSubmit}
|
||||
>
|
||||
Simpan
|
||||
</ButtonCustom>
|
||||
</BoxButtonOnFooter>
|
||||
);
|
||||
|
||||
@@ -31,22 +92,33 @@ export default function InvestmentAddDocument() {
|
||||
label="Judul Dokumen"
|
||||
placeholder="Masukan judul dokumen"
|
||||
required
|
||||
value={data.title}
|
||||
onChangeText={(value) => setData({ ...data, title: value })}
|
||||
/>
|
||||
|
||||
<BaseBox>
|
||||
<CenterCustom>
|
||||
<FontAwesome5
|
||||
name="file-pdf"
|
||||
size={30}
|
||||
color={MainColor.disabled}
|
||||
/>
|
||||
{pdf ? (
|
||||
<TextCustom truncate>{pdf.name}</TextCustom>
|
||||
) : (
|
||||
<FontAwesome5
|
||||
name="file-pdf"
|
||||
size={30}
|
||||
color={MainColor.disabled}
|
||||
/>
|
||||
)}
|
||||
</CenterCustom>
|
||||
</BaseBox>
|
||||
|
||||
<ButtonCenteredOnly
|
||||
icon="upload"
|
||||
onPress={() =>
|
||||
router.push("/(application)/(image)/take-picture/123")
|
||||
pickFile({
|
||||
allowedType: "pdf",
|
||||
setPdfUri(file) {
|
||||
setPdf(file);
|
||||
},
|
||||
})
|
||||
}
|
||||
>
|
||||
Upload
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import {
|
||||
BaseBox,
|
||||
BoxButtonOnFooter,
|
||||
@@ -7,17 +8,99 @@ import {
|
||||
InformationBox,
|
||||
Spacing,
|
||||
StackCustom,
|
||||
TextCustom,
|
||||
TextInputCustom,
|
||||
ViewWrapper,
|
||||
} from "@/components";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import { FontAwesome5 } from "@expo/vector-icons";
|
||||
import { router } from "expo-router";
|
||||
import DIRECTORY_ID from "@/constants/directory-id";
|
||||
import {
|
||||
apiInvestmentGetDocument,
|
||||
apiInvestmentUpsertDocument,
|
||||
} from "@/service/api-client/api-investment";
|
||||
import { deleteFileService, uploadFileService } from "@/service/upload-service";
|
||||
import pickFile from "@/utils/pickFile";
|
||||
import { router, useLocalSearchParams } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import { useEffect, useState } from "react";
|
||||
import Toast from "react-native-toast-message";
|
||||
|
||||
export default function InvestmentEditDocument() {
|
||||
const { id } = useLocalSearchParams();
|
||||
const [data, setData] = useState<any>(null);
|
||||
const [pdf, setPdf] = useState<any>(null);
|
||||
const [titleFile, setTitleFile] = useState<string>("");
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
onLoadData();
|
||||
}, [id]);
|
||||
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
const response = await apiInvestmentGetDocument({
|
||||
id: id as string,
|
||||
category: "one-document",
|
||||
});
|
||||
setData(response.data);
|
||||
setTitleFile(response.data.title);
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
}
|
||||
};
|
||||
|
||||
const handlerUpdate = async () => {
|
||||
const prevFileId = data.fileId;
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const responseUploadFile = await uploadFileService({
|
||||
dirId: DIRECTORY_ID.investasi_dokumen,
|
||||
imageUri: pdf.uri,
|
||||
});
|
||||
|
||||
if (!responseUploadFile.success) {
|
||||
throw new Error(responseUploadFile.message);
|
||||
}
|
||||
|
||||
const newData = {
|
||||
title: data.title,
|
||||
fileId: responseUploadFile.data.id,
|
||||
};
|
||||
|
||||
const response = await apiInvestmentUpsertDocument({
|
||||
id: id as string,
|
||||
data: newData,
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
const delPrevFile = await deleteFileService({
|
||||
id: prevFileId,
|
||||
});
|
||||
|
||||
console.log("[DEL PREV FILE]", delPrevFile);
|
||||
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: "Data berhasil diupdate",
|
||||
});
|
||||
|
||||
router.back();
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: "Gagal mengupdate data",
|
||||
});
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const buttonFooter = (
|
||||
<BoxButtonOnFooter>
|
||||
<ButtonCustom onPress={() => router.back()}>Update</ButtonCustom>
|
||||
<ButtonCustom isLoading={isLoading} disabled={!pdf} onPress={handlerUpdate}>
|
||||
Update
|
||||
</ButtonCustom>
|
||||
</BoxButtonOnFooter>
|
||||
);
|
||||
|
||||
@@ -31,22 +114,29 @@ export default function InvestmentEditDocument() {
|
||||
label="Judul Dokumen"
|
||||
placeholder="Masukan judul dokumen"
|
||||
required
|
||||
value={data?.title}
|
||||
onChangeText={(value) => setData({ ...data, title: value })}
|
||||
/>
|
||||
|
||||
<BaseBox>
|
||||
<CenterCustom>
|
||||
<FontAwesome5
|
||||
name="file-pdf"
|
||||
size={30}
|
||||
color={MainColor.disabled}
|
||||
/>
|
||||
{pdf ? (
|
||||
<TextCustom truncate>{pdf.name}</TextCustom>
|
||||
) : (
|
||||
<TextCustom truncate>{_.snakeCase(titleFile || "")}.pdf</TextCustom>
|
||||
)}
|
||||
</CenterCustom>
|
||||
</BaseBox>
|
||||
|
||||
<ButtonCenteredOnly
|
||||
icon="upload"
|
||||
onPress={() =>
|
||||
router.push("/(application)/(image)/take-picture/123")
|
||||
pickFile({
|
||||
allowedType: "pdf",
|
||||
setPdfUri(file) {
|
||||
setPdf(file);
|
||||
},
|
||||
})
|
||||
}
|
||||
>
|
||||
Upload
|
||||
|
||||
@@ -1,16 +1,58 @@
|
||||
import { ViewWrapper } from "@/components";
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import { LoaderCustom, TextCustom, ViewWrapper } from "@/components";
|
||||
import Investment_BoxDetailDocument from "@/screens/Invesment/Document/RecapBoxDetail";
|
||||
import { apiInvestmentGetDocument } from "@/service/api-client/api-investment";
|
||||
import { useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import { useCallback, useState } from "react";
|
||||
|
||||
export default function InvestmentListOfDocument() {
|
||||
const { id } = useLocalSearchParams();
|
||||
console.log("ID >> ", id);
|
||||
|
||||
const [list, setList] = useState<any[] | null>(null);
|
||||
const [loadList, setLoadList] = useState(false);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadListDocument();
|
||||
}, [id])
|
||||
);
|
||||
|
||||
const onLoadListDocument = async () => {
|
||||
try {
|
||||
setLoadList(true);
|
||||
const response = await apiInvestmentGetDocument({
|
||||
id: id as string,
|
||||
category: "all-document",
|
||||
});
|
||||
|
||||
setList(response.data);
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
setList([]);
|
||||
} finally {
|
||||
setLoadList(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<ViewWrapper>
|
||||
{Array.from({ length: 10 }).map((_, index) => (
|
||||
<Investment_BoxDetailDocument
|
||||
key={index}
|
||||
title={`Judul Dokumen ${index + 1}`}
|
||||
href={`/(file)/${index + 1}`}
|
||||
/>
|
||||
))}
|
||||
{loadList ? (
|
||||
<LoaderCustom />
|
||||
) : _.isEmpty(list) ? (
|
||||
<TextCustom align="center" color="gray">
|
||||
Tidak ada data
|
||||
</TextCustom>
|
||||
) : (
|
||||
list?.map((item: any, index: number) => (
|
||||
<Investment_BoxDetailDocument
|
||||
key={index}
|
||||
title={item.title}
|
||||
href={`/(file)/${item.fileId}`}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
</ViewWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,23 +1,90 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import {
|
||||
AlertDefaultSystem,
|
||||
BackButton,
|
||||
DotButton,
|
||||
DrawerCustom,
|
||||
LoaderCustom,
|
||||
MenuDrawerDynamicGrid,
|
||||
TextCustom,
|
||||
ViewWrapper,
|
||||
} from "@/components";
|
||||
import { IconEdit } from "@/components/_Icon";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import { ICON_SIZE_SMALL } from "@/constants/constans-value";
|
||||
import Investment_BoxDetailDocument from "@/screens/Invesment/Document/RecapBoxDetail";
|
||||
import {
|
||||
apiInvestmentDeleteDocument,
|
||||
apiInvestmentGetDocument,
|
||||
} from "@/service/api-client/api-investment";
|
||||
import { AntDesign, Ionicons } from "@expo/vector-icons";
|
||||
import { router, Stack, useLocalSearchParams } from "expo-router";
|
||||
import { useState } from "react";
|
||||
import {
|
||||
router,
|
||||
Stack,
|
||||
useFocusEffect,
|
||||
useLocalSearchParams,
|
||||
} from "expo-router";
|
||||
import _ from "lodash";
|
||||
import { useCallback, useState } from "react";
|
||||
import Toast from "react-native-toast-message";
|
||||
|
||||
export default function InvestmentRecapOfDocument() {
|
||||
const { id } = useLocalSearchParams();
|
||||
const [openDrawer, setOpenDrawer] = useState(false);
|
||||
const [openDrawerBox, setOpenDrawerBox] = useState(false);
|
||||
const [list, setList] = useState<any[] | null>(null);
|
||||
const [loadList, setLoadList] = useState(false);
|
||||
const [selectId, setSelectId] = useState<string | null>(null);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadListDocument();
|
||||
}, [id])
|
||||
);
|
||||
|
||||
const onLoadListDocument = async () => {
|
||||
try {
|
||||
setLoadList(true);
|
||||
const response = await apiInvestmentGetDocument({
|
||||
id: id as string,
|
||||
category: "all-document",
|
||||
});
|
||||
|
||||
setList(response.data);
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
setList([]);
|
||||
} finally {
|
||||
setLoadList(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handlerDeleteDocument = async () => {
|
||||
try {
|
||||
const response = await apiInvestmentDeleteDocument({
|
||||
id: selectId as string,
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: "Data berhasil dihapus",
|
||||
});
|
||||
setList((prev: any[] | null) => {
|
||||
if (!prev) return null;
|
||||
return prev.filter((item: any) => item.id !== selectId);
|
||||
});
|
||||
setOpenDrawerBox(false);
|
||||
setSelectId(null);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: "Gagal menghapus data",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -37,25 +104,36 @@ export default function InvestmentRecapOfDocument() {
|
||||
/>
|
||||
|
||||
<ViewWrapper>
|
||||
{Array.from({ length: 10 }).map((_, index) => (
|
||||
<Investment_BoxDetailDocument
|
||||
key={index}
|
||||
title={`Judul Dokumen ${index + 1}`}
|
||||
leftIcon={
|
||||
<Ionicons
|
||||
name="ellipsis-horizontal-outline"
|
||||
size={ICON_SIZE_SMALL}
|
||||
color={MainColor.white}
|
||||
style={{
|
||||
zIndex: 10,
|
||||
alignSelf: "flex-end",
|
||||
}}
|
||||
onPress={() => setOpenDrawerBox(true)}
|
||||
/>
|
||||
}
|
||||
href={`/(file)/${id}`}
|
||||
/>
|
||||
))}
|
||||
{loadList ? (
|
||||
<LoaderCustom />
|
||||
) : _.isEmpty(list) ? (
|
||||
<TextCustom align="center" color="gray">
|
||||
Tidak ada data
|
||||
</TextCustom>
|
||||
) : (
|
||||
list?.map((item: any, index: number) => (
|
||||
<Investment_BoxDetailDocument
|
||||
key={index}
|
||||
title={item.title}
|
||||
leftIcon={
|
||||
<Ionicons
|
||||
name="ellipsis-horizontal-outline"
|
||||
size={ICON_SIZE_SMALL}
|
||||
color={MainColor.white}
|
||||
style={{
|
||||
zIndex: 10,
|
||||
alignSelf: "flex-end",
|
||||
}}
|
||||
onPress={() => {
|
||||
setSelectId(item.id);
|
||||
setOpenDrawerBox(true);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
href={`/(file)/${item.fileId}`}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
</ViewWrapper>
|
||||
|
||||
{/* Drawer On Header */}
|
||||
@@ -69,7 +147,7 @@ export default function InvestmentRecapOfDocument() {
|
||||
{
|
||||
icon: (
|
||||
<AntDesign
|
||||
name="pluscircle"
|
||||
name="plus-circle"
|
||||
size={ICON_SIZE_SMALL}
|
||||
color={MainColor.white}
|
||||
/>
|
||||
@@ -96,7 +174,7 @@ export default function InvestmentRecapOfDocument() {
|
||||
{
|
||||
icon: <IconEdit />,
|
||||
label: "Edit Dokumen",
|
||||
path: `/investment/${id}/(document)/edit-document`,
|
||||
path: `/investment/${selectId}/(document)/edit-document`,
|
||||
},
|
||||
{
|
||||
icon: (
|
||||
@@ -119,12 +197,14 @@ export default function InvestmentRecapOfDocument() {
|
||||
textLeft: "Batal",
|
||||
textRight: "Hapus",
|
||||
onPressRight: () => {
|
||||
setOpenDrawerBox(false);
|
||||
handlerDeleteDocument();
|
||||
},
|
||||
});
|
||||
} else {
|
||||
router.push(item.path as any);
|
||||
}
|
||||
router.push(item.path as any);
|
||||
setOpenDrawer(false);
|
||||
|
||||
setOpenDrawerBox(false);
|
||||
}}
|
||||
/>
|
||||
</DrawerCustom>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import {
|
||||
BaseBox,
|
||||
BoxButtonOnFooter,
|
||||
@@ -9,16 +10,89 @@ import {
|
||||
TextInputCustom,
|
||||
ViewWrapper,
|
||||
} from "@/components";
|
||||
import { router, useLocalSearchParams } from "expo-router";
|
||||
import { LOCAL_STORAGE_KEY } from "@/constants/local-storage-key";
|
||||
import { apiInvestmentGetOne } from "@/service/api-client/api-investment";
|
||||
import { formatCurrencyDisplay } from "@/utils/formatCurrencyDisplay";
|
||||
import AsyncStorage from "@react-native-async-storage/async-storage";
|
||||
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import { useCallback, useState } from "react";
|
||||
|
||||
export default function InvestmentInvest() {
|
||||
const { id } = useLocalSearchParams();
|
||||
// console.log("[ID]", id);
|
||||
const [data, setData] = useState<any>(null);
|
||||
const [jumlah, setJumlah] = useState<number>(0);
|
||||
const [total, setTotal] = useState<number>(0);
|
||||
const [sisaLembar, setSisaLembar] = useState<number>(0);
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadData();
|
||||
}, [id])
|
||||
);
|
||||
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
const response = await apiInvestmentGetOne({
|
||||
id: id as string,
|
||||
});
|
||||
|
||||
setData(response.data);
|
||||
setSisaLembar(response.data?.sisaLembar);
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
}
|
||||
};
|
||||
|
||||
const handleTextChange = (text: string) => {
|
||||
// Izinkan input kosong → anggap sebagai 0 (atau abaikan, tergantung UX)
|
||||
if (text === "") {
|
||||
setJumlah(0);
|
||||
setTotal(0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Regex: hanya digit (angka bulat positif)
|
||||
const integerRegex = /^\d+$/;
|
||||
|
||||
if (integerRegex.test(text)) {
|
||||
const numValue = Number(text);
|
||||
// Karena regex sudah pastikan hanya angka, isNaN biasanya false
|
||||
// Tapi tetap aman untuk cek
|
||||
if (!isNaN(numValue)) {
|
||||
setJumlah(numValue);
|
||||
setTotal(numValue * Number(data?.hargaLembar));
|
||||
console.log("[VALUE]", numValue);
|
||||
}
|
||||
}
|
||||
// Jika input tidak valid (misal: "12a", "12."), abaikan → state tidak berubah
|
||||
};
|
||||
|
||||
const buttonSubmit = () => {
|
||||
return (
|
||||
<>
|
||||
<BoxButtonOnFooter>
|
||||
<ButtonCustom onPress={() => router.push(`/investment/${id}/select-bank`)}>Beli</ButtonCustom>
|
||||
<ButtonCustom
|
||||
isLoading={isLoading}
|
||||
disabled={jumlah < 10 || jumlah > sisaLembar}
|
||||
onPress={async () => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
await AsyncStorage.setItem(
|
||||
LOCAL_STORAGE_KEY.transactionInvestment,
|
||||
JSON.stringify({ jumlah, total })
|
||||
);
|
||||
router.push(`/investment/${id}/select-bank`);
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}}
|
||||
>
|
||||
Beli
|
||||
</ButtonCustom>
|
||||
</BoxButtonOnFooter>
|
||||
</>
|
||||
);
|
||||
@@ -34,7 +108,7 @@ export default function InvestmentInvest() {
|
||||
<TextCustom>Sisa Lembar Saham</TextCustom>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={6} style={{ alignItems: "flex-end" }}>
|
||||
<TextCustom>3.000</TextCustom>
|
||||
<TextCustom>{data?.sisaLembar || "-"}</TextCustom>
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
<Grid>
|
||||
@@ -42,7 +116,7 @@ export default function InvestmentInvest() {
|
||||
<TextCustom>Harga Per Lembar</TextCustom>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={6} style={{ alignItems: "flex-end" }}>
|
||||
<TextCustom>Rp. 1.000</TextCustom>
|
||||
<TextCustom>{data?.hargaLembar || "-"}</TextCustom>
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
<Grid>
|
||||
@@ -69,6 +143,10 @@ export default function InvestmentInvest() {
|
||||
}}
|
||||
placeholder="0"
|
||||
keyboardType="numeric"
|
||||
value={jumlah.toString()}
|
||||
onChangeText={(value) => {
|
||||
handleTextChange(value);
|
||||
}}
|
||||
/>
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
@@ -78,7 +156,7 @@ export default function InvestmentInvest() {
|
||||
<TextCustom>Total Harga</TextCustom>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={6} style={{ alignItems: "flex-end" }}>
|
||||
<TextCustom>Rp. 1.000</TextCustom>
|
||||
<TextCustom> Rp. {formatCurrencyDisplay(total)}</TextCustom>
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
</StackCustom>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import {
|
||||
BaseBox,
|
||||
ButtonCenteredOnly,
|
||||
@@ -9,11 +10,96 @@ import {
|
||||
TextCustom,
|
||||
ViewWrapper,
|
||||
} from "@/components";
|
||||
import CopyButton from "@/components/Button/CoyButton";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import { router, useLocalSearchParams } from "expo-router";
|
||||
import DIRECTORY_ID from "@/constants/directory-id";
|
||||
import {
|
||||
apiInvestmentGetInvoice,
|
||||
apiInvestmentUpdateInvoice,
|
||||
} from "@/service/api-client/api-investment";
|
||||
import { uploadFileService } from "@/service/upload-service";
|
||||
import { formatCurrencyDisplay } from "@/utils/formatCurrencyDisplay";
|
||||
import pickFile, { IFileData } from "@/utils/pickFile";
|
||||
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import { useCallback, useState } from "react";
|
||||
import { View } from "react-native";
|
||||
import Toast from "react-native-toast-message";
|
||||
|
||||
export default function InvestmentInvoice() {
|
||||
const { id } = useLocalSearchParams();
|
||||
console.log("[ID]", id);
|
||||
const [data, setData] = useState<any>({});
|
||||
const [image, setImage] = useState<IFileData>({
|
||||
name: "",
|
||||
uri: "",
|
||||
size: 0,
|
||||
});
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadData();
|
||||
}, [id])
|
||||
);
|
||||
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
const response = await apiInvestmentGetInvoice({
|
||||
id: id as string,
|
||||
category: "invoice",
|
||||
});
|
||||
|
||||
console.log("[RES INVOICE]", JSON.stringify(response.data, null, 2));
|
||||
setData(response.data);
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
}
|
||||
};
|
||||
|
||||
const handlerSubmitUpdate = async () => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const responseUploadImage = await uploadFileService({
|
||||
dirId: DIRECTORY_ID.investasi_bukti_transfer,
|
||||
imageUri: image?.uri,
|
||||
});
|
||||
|
||||
console.log("[RESPONSE UPLOAD IMAGE]", responseUploadImage);
|
||||
|
||||
if (!responseUploadImage?.data?.id) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: "Gagal mengunggah bukti transfer",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const response = await apiInvestmentUpdateInvoice({
|
||||
id: id as string,
|
||||
data: {
|
||||
imageId: responseUploadImage?.data?.id,
|
||||
},
|
||||
status: "proses",
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
console.log(
|
||||
"[RESPONSE UPDATE]",
|
||||
JSON.stringify(response.data, null, 2)
|
||||
);
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: "Berhasil mengunggah bukti transfer",
|
||||
});
|
||||
router.push(`/investment/${id}/(transaction-flow)/process`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ViewWrapper>
|
||||
@@ -21,9 +107,23 @@ export default function InvestmentInvoice() {
|
||||
<InformationBox text="Mohon transfer ke rekening dibawah" />
|
||||
<BaseBox>
|
||||
<StackCustom gap={"xs"}>
|
||||
<TextCustom>Nama BANK</TextCustom>
|
||||
<TextCustom>Nama Penerima</TextCustom>
|
||||
<Grid>
|
||||
<Grid.Col span={4}>
|
||||
<TextCustom>Bank</TextCustom>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={8}>
|
||||
<TextCustom>{data?.MasterBank?.namaBank}</TextCustom>
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
<Spacing height={10} />
|
||||
<Grid>
|
||||
<Grid.Col span={4}>
|
||||
<TextCustom>Nama Akun</TextCustom>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={8}>
|
||||
<TextCustom>{data?.MasterBank?.namaAkun}</TextCustom>
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
|
||||
<BaseBox backgroundColor={MainColor.soft_darkblue}>
|
||||
<Grid containerStyle={{ justifyContent: "center" }}>
|
||||
@@ -34,7 +134,7 @@ export default function InvestmentInvoice() {
|
||||
}}
|
||||
>
|
||||
<TextCustom size="xlarge" bold color="yellow">
|
||||
4567898765433567
|
||||
{data?.MasterBank?.norek}
|
||||
</TextCustom>
|
||||
</Grid.Col>
|
||||
<Grid.Col
|
||||
@@ -43,7 +143,7 @@ export default function InvestmentInvoice() {
|
||||
alignItems: "flex-end",
|
||||
}}
|
||||
>
|
||||
<ButtonCustom>Salin</ButtonCustom>
|
||||
<CopyButton textToCopy={data?.MasterBank?.norek} />
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
</BaseBox>
|
||||
@@ -65,7 +165,7 @@ export default function InvestmentInvoice() {
|
||||
}}
|
||||
>
|
||||
<TextCustom size="xlarge" bold color="yellow">
|
||||
Rp. 1.000.000
|
||||
Rp. {formatCurrencyDisplay(data?.nominal)}
|
||||
</TextCustom>
|
||||
</Grid.Col>
|
||||
<Grid.Col
|
||||
@@ -74,7 +174,7 @@ export default function InvestmentInvoice() {
|
||||
alignItems: "flex-end",
|
||||
}}
|
||||
>
|
||||
<ButtonCustom>Salin</ButtonCustom>
|
||||
<CopyButton textToCopy={data?.nominal} />
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
</BaseBox>
|
||||
@@ -83,10 +183,37 @@ export default function InvestmentInvoice() {
|
||||
|
||||
<BaseBox>
|
||||
<StackCustom>
|
||||
<TextCustom>Upload bukti transfer anda.</TextCustom>
|
||||
<TextCustom align="center">
|
||||
Upload bukti transfer anda.
|
||||
</TextCustom>
|
||||
{image ? (
|
||||
<View
|
||||
style={{
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
gap: 10,
|
||||
paddingInline: 20,
|
||||
}}
|
||||
>
|
||||
<TextCustom bold align="center" truncate>
|
||||
{image?.name}
|
||||
</TextCustom>
|
||||
</View>
|
||||
) : (
|
||||
<TextCustom align="center">
|
||||
Tidak ada gambar yang diunggah
|
||||
</TextCustom>
|
||||
)}
|
||||
<ButtonCenteredOnly
|
||||
onPress={() => {
|
||||
router.push("/(application)/(image)/take-picture/123");
|
||||
pickFile({
|
||||
allowedType: "image",
|
||||
setImageUri(file: any) {
|
||||
console.log("[IMAGE]", file);
|
||||
setImage(file);
|
||||
},
|
||||
});
|
||||
}}
|
||||
icon="upload"
|
||||
>
|
||||
@@ -96,14 +223,16 @@ export default function InvestmentInvoice() {
|
||||
</BaseBox>
|
||||
|
||||
<ButtonCustom
|
||||
isLoading={isLoading}
|
||||
disabled={!image}
|
||||
onPress={() => {
|
||||
router.push(`/investment/${id}/(transaction-flow)/process`);
|
||||
handlerSubmitUpdate();
|
||||
}}
|
||||
>
|
||||
Saya Sudah Transfer
|
||||
</ButtonCustom>
|
||||
</StackCustom>
|
||||
<Spacing/>
|
||||
<Spacing />
|
||||
</ViewWrapper>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import {
|
||||
BaseBox,
|
||||
Grid,
|
||||
StackCustom,
|
||||
TextCustom,
|
||||
ViewWrapper,
|
||||
ViewWrapper
|
||||
} from "@/components";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
import { ActivityIndicator } from "react-native";
|
||||
|
||||
export default function InvestmentProcess() {
|
||||
@@ -16,21 +14,22 @@ export default function InvestmentProcess() {
|
||||
<BaseBox>
|
||||
<StackCustom>
|
||||
<TextCustom align="center" bold>
|
||||
Admin sedang memproses transaksi investasimu
|
||||
Admin sedang memvalidasi data dan bukti transfer anda. Mohon
|
||||
tunggu proses ini selesai.
|
||||
</TextCustom>
|
||||
<ActivityIndicator size="large" color={MainColor.yellow} />
|
||||
</StackCustom>
|
||||
</BaseBox>
|
||||
|
||||
<BaseBox>
|
||||
{/* <BaseBox>
|
||||
<Grid>
|
||||
<Grid.Col span={10} style={{justifyContent: 'center'}}>
|
||||
<Grid.Col span={10} style={{ justifyContent: "center" }}>
|
||||
<TextCustom size="small">
|
||||
Hubungi admin jika tidak kunjung di proses! Klik pada logo
|
||||
Whatsapp ini.
|
||||
</TextCustom>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={2} style={{alignItems: "flex-end"}}>
|
||||
<Grid.Col span={2} style={{ alignItems: "flex-end" }}>
|
||||
<Ionicons
|
||||
name="logo-whatsapp"
|
||||
size={50}
|
||||
@@ -38,7 +37,7 @@ export default function InvestmentProcess() {
|
||||
/>
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
</BaseBox>
|
||||
</BaseBox> */}
|
||||
</ViewWrapper>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -5,35 +5,97 @@ import {
|
||||
ViewWrapper,
|
||||
} from "@/components";
|
||||
import { RadioCustom, RadioGroup } from "@/components/Radio/RadioCustom";
|
||||
import { dummyMasterBank } from "@/lib/dummy-data/_master/bank";
|
||||
import { LOCAL_STORAGE_KEY } from "@/constants/local-storage-key";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import { apiInvestmentCreateInvoice } from "@/service/api-client/api-investment";
|
||||
import { apiMasterBank } from "@/service/api-client/api-master";
|
||||
import AsyncStorage from "@react-native-async-storage/async-storage";
|
||||
import { router, useLocalSearchParams } from "expo-router";
|
||||
import { useState } from "react";
|
||||
import _ from "lodash";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export default function InvestmentSelectBank() {
|
||||
const { user } = useAuth();
|
||||
const { id } = useLocalSearchParams();
|
||||
const [value, setValue] = useState<any | number>("");
|
||||
const [select, setSelect] = useState<any | number>("");
|
||||
const [listBank, setListBank] = useState<any>([]);
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
loadListBank();
|
||||
}, []);
|
||||
|
||||
const loadListBank = async () => {
|
||||
try {
|
||||
const response = await apiMasterBank();
|
||||
|
||||
setListBank(response.data);
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
setListBank([]);
|
||||
}
|
||||
};
|
||||
|
||||
const handlerSubmit = async () => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const dataCheckout = await AsyncStorage.getItem(
|
||||
LOCAL_STORAGE_KEY.transactionInvestment
|
||||
);
|
||||
if (dataCheckout) {
|
||||
const storage = JSON.parse(dataCheckout);
|
||||
const newData = {
|
||||
...storage,
|
||||
bankId: select,
|
||||
authorId: user?.id,
|
||||
};
|
||||
|
||||
const response = await apiInvestmentCreateInvoice({
|
||||
id: id as string,
|
||||
data: newData,
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
console.log("[RESPONSE >>]", response);
|
||||
const invoiceId = response.data.id;
|
||||
|
||||
const delStorage = await AsyncStorage.removeItem(
|
||||
LOCAL_STORAGE_KEY.transactionInvestment
|
||||
);
|
||||
|
||||
console.log("[DEL STORAGE]", delStorage);
|
||||
router.replace(`/investment/${invoiceId}/invoice`);
|
||||
} else {
|
||||
console.log("[FAILED]", response);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const buttonSubmit = () => {
|
||||
return (
|
||||
<>
|
||||
<BoxButtonOnFooter>
|
||||
<ButtonCustom
|
||||
onPress={() => router.replace(`/investment/${id}/invoice`)}
|
||||
>
|
||||
Pilih
|
||||
</ButtonCustom>
|
||||
<ButtonCustom isLoading={isLoading} onPress={() => handlerSubmit()}>Pilih</ButtonCustom>
|
||||
</BoxButtonOnFooter>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<ViewWrapper footerComponent={buttonSubmit()}>
|
||||
<RadioGroup value={value} onChange={setValue}>
|
||||
{dummyMasterBank.map((item) => (
|
||||
<BaseBox key={item.name}>
|
||||
<RadioCustom label={item.name} value={item.code} />
|
||||
</BaseBox>
|
||||
))}
|
||||
<RadioGroup value={select} onChange={setSelect}>
|
||||
{_.isEmpty(listBank)
|
||||
? []
|
||||
: listBank?.map((item: any) => (
|
||||
<BaseBox key={item.id}>
|
||||
<RadioCustom label={item.namaBank} value={item.id} />
|
||||
</BaseBox>
|
||||
))}
|
||||
</RadioGroup>
|
||||
</ViewWrapper>
|
||||
);
|
||||
|
||||
@@ -10,10 +10,11 @@ import { IconDocument, IconEdit, IconNews } from "@/components/_Icon";
|
||||
import { IMenuDrawerItem } from "@/components/_Interface/types";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import { ICON_SIZE_MEDIUM } from "@/constants/constans-value";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import Investment_ButtonInvestasiSection from "@/screens/Invesment/ButtonInvestasiSection";
|
||||
import Invesment_ComponentBoxOnBottomDetail from "@/screens/Invesment/ComponentBoxOnBottomDetail";
|
||||
import Invesment_DetailDataPublishSection from "@/screens/Invesment/DetailDataPublishSection";
|
||||
import { apiInvestmentGetById } from "@/service/api-client/api-investment";
|
||||
import { apiInvestmentGetOne } from "@/service/api-client/api-investment";
|
||||
import { AntDesign, MaterialIcons } from "@expo/vector-icons";
|
||||
import {
|
||||
router,
|
||||
@@ -25,6 +26,7 @@ import _ from "lodash";
|
||||
import { useCallback, useState } from "react";
|
||||
|
||||
export default function InvestmentDetailStatus() {
|
||||
const { user } = useAuth();
|
||||
const { id, status } = useLocalSearchParams();
|
||||
const [openDrawerDraft, setOpenDrawerDraft] = useState(false);
|
||||
const [openDrawerPublish, setOpenDrawerPublish] = useState(false);
|
||||
@@ -39,7 +41,7 @@ export default function InvestmentDetailStatus() {
|
||||
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
const response = await apiInvestmentGetById({
|
||||
const response = await apiInvestmentGetOne({
|
||||
id: id as string,
|
||||
});
|
||||
|
||||
@@ -70,7 +72,7 @@ export default function InvestmentDetailStatus() {
|
||||
);
|
||||
|
||||
const buttonSection = (
|
||||
<Investment_ButtonInvestasiSection id={id as string} isMine={false} />
|
||||
<Investment_ButtonInvestasiSection id={id as string} isMine={user?.id === data?.author?.id} />
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
} from "@/components";
|
||||
import DIRECTORY_ID from "@/constants/directory-id";
|
||||
import {
|
||||
apiInvestmentGetById,
|
||||
apiInvestmentGetOne,
|
||||
apiInvestmentUpdateData,
|
||||
} from "@/service/api-client/api-investment";
|
||||
import { deleteFileService, uploadFileService } from "@/service/upload-service";
|
||||
@@ -40,7 +40,7 @@ export default function InvestmentEditProspectus() {
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
setLoadingGet(true);
|
||||
const response = await apiInvestmentGetById({
|
||||
const response = await apiInvestmentGetOne({
|
||||
id: id as string,
|
||||
});
|
||||
setData(response.data);
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
import API_STRORAGE from "@/constants/base-url-api-strorage";
|
||||
import DIRECTORY_ID from "@/constants/directory-id";
|
||||
import {
|
||||
apiInvestmentGetById,
|
||||
apiInvestmentGetOne,
|
||||
apiInvestmentUpdateData,
|
||||
} from "@/service/api-client/api-investment";
|
||||
import { apiMasterInvestment } from "@/service/api-client/api-master";
|
||||
@@ -90,7 +90,7 @@ export default function InvestmentEdit() {
|
||||
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
const response = await apiInvestmentGetById({
|
||||
const response = await apiInvestmentGetOne({
|
||||
id: id as string,
|
||||
});
|
||||
setData(response.data);
|
||||
@@ -101,9 +101,8 @@ export default function InvestmentEdit() {
|
||||
|
||||
const displayTargetDana = formatCurrencyDisplay(data?.targetDana);
|
||||
const displayHargaPerLembar = formatCurrencyDisplay(data?.hargaLembar);
|
||||
const displayTotalLembar = formatCurrencyDisplay(
|
||||
Number(data?.targetDana) / Number(data?.hargaLembar)
|
||||
);
|
||||
const realTotalLembar = Number(data?.targetDana) / Number(data?.hargaLembar);
|
||||
const displayTotalLembar = formatCurrencyDisplay(realTotalLembar);
|
||||
|
||||
const handleChangeCurrency = (field: keyof typeof data) => (text: string) => {
|
||||
const numeric = text.replace(/\D/g, "");
|
||||
@@ -134,6 +133,7 @@ export default function InvestmentEdit() {
|
||||
const handleSubmitUpdate = async () => {
|
||||
let newData = {
|
||||
...data,
|
||||
totalLembar: realTotalLembar.toString(),
|
||||
};
|
||||
|
||||
if (!validateData()) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import {
|
||||
BackButton,
|
||||
DotButton,
|
||||
@@ -9,18 +10,45 @@ import { IconDocument, IconEdit, IconNews } from "@/components/_Icon";
|
||||
import { IMenuDrawerItem } from "@/components/_Interface/types";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import { ICON_SIZE_MEDIUM } from "@/constants/constans-value";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import Investment_ButtonInvestasiSection from "@/screens/Invesment/ButtonInvestasiSection";
|
||||
import Invesment_ComponentBoxOnBottomDetail from "@/screens/Invesment/ComponentBoxOnBottomDetail";
|
||||
import Invesment_DetailDataPublishSection from "@/screens/Invesment/DetailDataPublishSection";
|
||||
import { apiInvestmentGetOne } from "@/service/api-client/api-investment";
|
||||
import { AntDesign, MaterialIcons } from "@expo/vector-icons";
|
||||
import { router, Stack, useLocalSearchParams } from "expo-router";
|
||||
import {
|
||||
router,
|
||||
Stack,
|
||||
useFocusEffect,
|
||||
useLocalSearchParams,
|
||||
} from "expo-router";
|
||||
import _ from "lodash";
|
||||
import { useState } from "react";
|
||||
import { useCallback, useState } from "react";
|
||||
|
||||
export default function InvestmentDetail() {
|
||||
const { user } = useAuth();
|
||||
const { id, status } = useLocalSearchParams();
|
||||
const [openDrawerDraft, setOpenDrawerDraft] = useState(false);
|
||||
const [openDrawerPublish, setOpenDrawerPublish] = useState(false);
|
||||
const [data, setData] = useState<any>(null);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadData();
|
||||
}, [id, status])
|
||||
);
|
||||
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
const response = await apiInvestmentGetOne({
|
||||
id: id as string,
|
||||
});
|
||||
|
||||
setData(response.data);
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
}
|
||||
};
|
||||
|
||||
const handlePressDraft = (item: IMenuDrawerItem) => {
|
||||
console.log("PATH >> ", item.path);
|
||||
@@ -37,11 +65,14 @@ export default function InvestmentDetail() {
|
||||
const bottomSection = (
|
||||
<Invesment_ComponentBoxOnBottomDetail
|
||||
id={id as string}
|
||||
status={'publish'}
|
||||
prospectusId={data?.prospektusFileId}
|
||||
status={"publish"}
|
||||
/>
|
||||
);
|
||||
|
||||
const buttonSection = <Investment_ButtonInvestasiSection id={id as string} isMine={true} />;
|
||||
const buttonSection = (
|
||||
<Investment_ButtonInvestasiSection id={id as string} isMine={user?.id === data?.author?.id} />
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -61,6 +92,7 @@ export default function InvestmentDetail() {
|
||||
<ViewWrapper>
|
||||
<Invesment_DetailDataPublishSection
|
||||
status={"publish"}
|
||||
data={data}
|
||||
bottomSection={bottomSection}
|
||||
buttonSection={buttonSection}
|
||||
/>
|
||||
|
||||
@@ -74,9 +74,8 @@ export default function InvestmentCreate() {
|
||||
|
||||
const displayTargetDana = formatCurrencyDisplay(data.targetDana);
|
||||
const displayHargaPerLembar = formatCurrencyDisplay(data.hargaPerLembar);
|
||||
const displayTotalLembar = formatCurrencyDisplay(
|
||||
Number(data.targetDana) / Number(data.hargaPerLembar)
|
||||
);
|
||||
const realTotalLembar = Number(data.targetDana) / Number(data.hargaPerLembar);
|
||||
const displayTotalLembar = formatCurrencyDisplay(realTotalLembar);
|
||||
|
||||
const handleChangeCurrency = (field: keyof typeof data) => (text: string) => {
|
||||
const numeric = text.replace(/\D/g, "");
|
||||
@@ -150,7 +149,7 @@ export default function InvestmentCreate() {
|
||||
title: data.title,
|
||||
targetDana: data.targetDana,
|
||||
hargaLembar: data.hargaPerLembar,
|
||||
totalLembar: displayTotalLembar,
|
||||
totalLembar: realTotalLembar.toString(),
|
||||
roi: data.rasioKeuntungan,
|
||||
masterPencarianInvestorId: data.pencarianInvestor,
|
||||
masterPembagianDevidenId: data.pembagianDeviden,
|
||||
|
||||
72
components/Button/CoyButton.tsx
Normal file
72
components/Button/CoyButton.tsx
Normal file
@@ -0,0 +1,72 @@
|
||||
import React, { useState } from "react";
|
||||
import { TouchableOpacity, Text, StyleSheet } from "react-native";
|
||||
import * as Clipboard from "expo-clipboard";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
|
||||
interface CopyButtonProps {
|
||||
textToCopy: string;
|
||||
copyLabel?: string; // Teks tombol saat normal, default: "Copy"
|
||||
copiedLabel?: string; // Teks tombol saat berhasil, default: "Copied!"
|
||||
onCopySuccess?: () => void; // Callback opsional saat berhasil menyalin
|
||||
duration?: number; // Durasi (ms) menampilkan "Copied!", default: 2000
|
||||
style?: any; // Gaya tambahan untuk tombol
|
||||
textStyle?: any; // Gaya tambahan untuk teks
|
||||
}
|
||||
|
||||
const CopyButton: React.FC<CopyButtonProps> = ({
|
||||
textToCopy,
|
||||
copyLabel = "Copy",
|
||||
copiedLabel = "Copied!",
|
||||
onCopySuccess,
|
||||
duration = 2000,
|
||||
style,
|
||||
textStyle,
|
||||
}) => {
|
||||
const [isCopied, setIsCopied] = useState(false);
|
||||
|
||||
const handleCopy = async () => {
|
||||
try {
|
||||
await Clipboard.setStringAsync(textToCopy);
|
||||
setIsCopied(true);
|
||||
onCopySuccess?.();
|
||||
|
||||
// Reset kembali ke label "Copy" setelah durasi tertentu
|
||||
setTimeout(() => {
|
||||
setIsCopied(false);
|
||||
}, duration);
|
||||
} catch (error) {
|
||||
console.error("Failed to copy text:", error);
|
||||
// Opsional: tampilkan error toast jika diperlukan
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<TouchableOpacity
|
||||
style={[styles.button, style]}
|
||||
onPress={handleCopy}
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
<Text style={[styles.text, textStyle]}>
|
||||
{isCopied ? copiedLabel : copyLabel}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
button: {
|
||||
backgroundColor: MainColor.yellow,
|
||||
paddingHorizontal: 16,
|
||||
paddingVertical: 8,
|
||||
borderRadius: 50,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
},
|
||||
text: {
|
||||
color: MainColor.darkblue,
|
||||
fontWeight: "600",
|
||||
fontSize: 14,
|
||||
},
|
||||
});
|
||||
|
||||
export default CopyButton;
|
||||
4
constants/local-storage-key.ts
Normal file
4
constants/local-storage-key.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export const LOCAL_STORAGE_KEY = {
|
||||
transactionInvestment: "transactionInvestment",
|
||||
transactionDonation: "transactionDonation",
|
||||
};
|
||||
@@ -17,15 +17,15 @@ const listDataNotPublishInvesment = ({ data }: { data: any }) => [
|
||||
},
|
||||
{
|
||||
label: "Total Lembar",
|
||||
value: data?.totalLembar || "-",
|
||||
value: formatCurrencyDisplay(data?.totalLembar) || "-",
|
||||
},
|
||||
{
|
||||
label: "Pencarian Investor",
|
||||
value: data && data?.MasterPencarianInvestor?.name + " hari" || "-",
|
||||
value: (data && data?.MasterPencarianInvestor?.name + " hari") || "-",
|
||||
},
|
||||
{
|
||||
label: "Jadwal Pembagian",
|
||||
value: data && data?.MasterPembagianDeviden?.name + " bulan" || "-",
|
||||
value: (data && data?.MasterPembagianDeviden?.name + " bulan") || "-",
|
||||
},
|
||||
{
|
||||
label: "Pembagian Deviden",
|
||||
@@ -40,34 +40,34 @@ const listDataPublishInvesment = ({ data }: { data: any }) => [
|
||||
},
|
||||
{
|
||||
label: "Target Dana",
|
||||
value: data?.targetDana,
|
||||
value: `Rp. ${formatCurrencyDisplay(data?.targetDana) || "-"}`,
|
||||
},
|
||||
{
|
||||
label: "Harga Per Lembar",
|
||||
value: data?.hargaPerLembar,
|
||||
value: `Rp. ${formatCurrencyDisplay(data?.hargaLembar) || "-"}`,
|
||||
},
|
||||
{
|
||||
label: "Return Of Investment (ROI)",
|
||||
value: data?.roi + " %",
|
||||
value: `${data?.roi || "-"} %`,
|
||||
},
|
||||
{
|
||||
label: "Total Lembar",
|
||||
value: data?.totalLembar,
|
||||
value: formatCurrencyDisplay(data?.totalLembar) || "-",
|
||||
},
|
||||
{
|
||||
label: "Sisa Lembar",
|
||||
value: data?.sisaLembar,
|
||||
},
|
||||
{
|
||||
label: "Jadwal Pembagian",
|
||||
value: data?.jadwalPembagian,
|
||||
},
|
||||
{
|
||||
label: "Pembagian Deviden",
|
||||
value: data?.pembagianDeviden,
|
||||
value: formatCurrencyDisplay(data?.sisaLembar) || "-",
|
||||
},
|
||||
{
|
||||
label: "Pencarian Investor",
|
||||
value: data?.pencarianInvestor,
|
||||
value: (data && data?.MasterPencarianInvestor?.name + " hari") || "-",
|
||||
},
|
||||
{
|
||||
label: "Jadwal Pembagian",
|
||||
value: (data && data?.MasterPembagianDeviden?.name + " bulan") || "-",
|
||||
},
|
||||
{
|
||||
label: "Pembagian Deviden",
|
||||
value: data?.MasterPeriodeDeviden?.name || "-",
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1,28 +1,40 @@
|
||||
import {
|
||||
BaseBox,
|
||||
AvatarUsernameAndOtherComponent,
|
||||
BoxWithHeaderSection,
|
||||
DummyLandscapeImage,
|
||||
Grid,
|
||||
Spacing,
|
||||
StackCustom,
|
||||
TextCustom,
|
||||
TextCustom
|
||||
} from "@/components";
|
||||
import { View } from "react-native";
|
||||
|
||||
export default function Invesment_BoxDetailDataSection({
|
||||
title,
|
||||
author,
|
||||
imageId,
|
||||
data,
|
||||
bottomSection,
|
||||
}: {
|
||||
title?: string;
|
||||
author?: any;
|
||||
imageId?: string;
|
||||
data: any;
|
||||
bottomSection?: React.ReactNode;
|
||||
}) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<BaseBox paddingBottom={0}>
|
||||
<BoxWithHeaderSection>
|
||||
<StackCustom gap={"xs"}>
|
||||
{author && (
|
||||
<AvatarUsernameAndOtherComponent
|
||||
avatar={author?.Profile?.imageId}
|
||||
name={author?.username}
|
||||
rightComponent={""}
|
||||
withBottomLine={true}
|
||||
/>
|
||||
)}
|
||||
<DummyLandscapeImage imageId={imageId} />
|
||||
<Spacing />
|
||||
<TextCustom align="center" size="xlarge" bold>
|
||||
@@ -46,7 +58,7 @@ export default function Invesment_BoxDetailDataSection({
|
||||
<Spacing />
|
||||
{bottomSection}
|
||||
</StackCustom>
|
||||
</BaseBox>
|
||||
</BoxWithHeaderSection>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { BaseBox, StackCustom, TextCustom, ProgressCustom } from "@/components";
|
||||
|
||||
export default function Invesment_BoxProgressSection({status}: {status: string}) {
|
||||
export default function Invesment_BoxProgressSection({progress, status}: {progress: number, status: string}) {
|
||||
return (
|
||||
<>
|
||||
{status === "publish" && (
|
||||
<BaseBox>
|
||||
<StackCustom>
|
||||
<TextCustom bold>Progress Saham</TextCustom>
|
||||
<ProgressCustom value={70} size="lg" />
|
||||
<ProgressCustom label={progress + "%"} value={progress} size="lg" />
|
||||
</StackCustom>
|
||||
</BaseBox>
|
||||
)}
|
||||
|
||||
@@ -8,9 +8,12 @@ export default function Investment_ButtonInvestasiSection({
|
||||
id: string;
|
||||
isMine: boolean;
|
||||
}) {
|
||||
console.log("[IS MINE]", isMine);
|
||||
return (
|
||||
<>
|
||||
{isMine ? (
|
||||
<ButtonCustom disabled>Investasi Ini Milik Anda</ButtonCustom>
|
||||
) : (
|
||||
<ButtonCustom
|
||||
onPress={() => {
|
||||
router.navigate(`/investment/${id}/(transaction-flow)`);
|
||||
@@ -18,8 +21,6 @@ export default function Investment_ButtonInvestasiSection({
|
||||
>
|
||||
Beli Saham
|
||||
</ButtonCustom>
|
||||
) : (
|
||||
<ButtonCustom disabled>Investasi Ini Milik Anda</ButtonCustom>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -3,7 +3,6 @@ import {
|
||||
apiInvestmentDelete,
|
||||
apiInvestmentUpdateStatus,
|
||||
} from "@/service/api-client/api-investment";
|
||||
import { deleteFileService } from "@/service/upload-service";
|
||||
import { router } from "expo-router";
|
||||
import { useState } from "react";
|
||||
import Toast from "react-native-toast-message";
|
||||
@@ -136,36 +135,14 @@ export default function Investment_ButtonStatusSection({
|
||||
id: id as string,
|
||||
});
|
||||
|
||||
console.log("[RESPONSE]", JSON.stringify(response, null, 2));
|
||||
console.log("[RESPONSE DELETE]", JSON.stringify(response, null, 2));
|
||||
|
||||
if (response.success) {
|
||||
const deleteImage = await deleteFileService({
|
||||
id: response?.data?.imageId as string,
|
||||
});
|
||||
|
||||
if (!deleteImage.success) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: "Gagal Hapus Data",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const deleteFile = await deleteFileService({
|
||||
id: response?.data?.prospektusFileId as string,
|
||||
});
|
||||
|
||||
if (!deleteFile.success) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: "Gagal Hapus Data",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: "Berhasil Hapus Data",
|
||||
});
|
||||
|
||||
router.back();
|
||||
} else {
|
||||
Toast.show({
|
||||
|
||||
@@ -18,7 +18,6 @@ export default function Invesment_ComponentBoxOnBottomDetail({
|
||||
prospectusId: string;
|
||||
status: string;
|
||||
}) {
|
||||
|
||||
return (
|
||||
<>
|
||||
{status === "publish" ? (
|
||||
@@ -28,7 +27,7 @@ export default function Invesment_ComponentBoxOnBottomDetail({
|
||||
<BaseBox
|
||||
backgroundColor={AccentColor.blue}
|
||||
style={{ borderColor: AccentColor.softblue, borderWidth: 1 }}
|
||||
href={`/(file)/${id}`}
|
||||
href={`/(file)/${prospectusId}`}
|
||||
>
|
||||
<StackCustom>
|
||||
<TextCustom align="center">Prospektus</TextCustom>
|
||||
|
||||
@@ -19,13 +19,14 @@ export default function Invesment_DetailDataPublishSection({
|
||||
bottomSection?: React.ReactNode;
|
||||
buttonSection?: React.ReactNode;
|
||||
}) {
|
||||
// console.log("[DATA DETAIL]", JSON.stringify(data, null, 2));
|
||||
|
||||
return (
|
||||
<>
|
||||
<StackCustom gap={"sm"}>
|
||||
<Invesment_BoxProgressSection status={status as string} />
|
||||
<Invesment_BoxProgressSection progress={data?.progress} status={status as string} />
|
||||
<Invesment_BoxDetailDataSection
|
||||
title={data?.title}
|
||||
author={data?.author}
|
||||
imageId={data?.imageId}
|
||||
data={
|
||||
status === "publish"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { BaseBox, Grid, TextCustom } from "@/components";
|
||||
import { Href } from "expo-router";
|
||||
import { BaseBox, ClickableCustom, Grid, TextCustom } from "@/components";
|
||||
import { Href, router } from "expo-router";
|
||||
|
||||
export default function Investment_BoxDetailDocument({
|
||||
title,
|
||||
@@ -8,17 +8,19 @@ export default function Investment_BoxDetailDocument({
|
||||
}: {
|
||||
title: string;
|
||||
leftIcon?: React.ReactNode;
|
||||
href?: Href;
|
||||
href?: Href | string;
|
||||
}) {
|
||||
return (
|
||||
<>
|
||||
<BaseBox href={href}>
|
||||
<BaseBox>
|
||||
<Grid>
|
||||
<Grid.Col span={leftIcon ? 10 : 12}>
|
||||
<TextCustom truncate>
|
||||
{title ||
|
||||
`Judul Dokumen: Lorem, ipsum dolor sit amet consectetur adipisicing elit.`}
|
||||
</TextCustom>
|
||||
<ClickableCustom onPress={() => router.push(href as any)}>
|
||||
<TextCustom truncate>
|
||||
{title ||
|
||||
`Judul Dokumen: Lorem, ipsum dolor sit amet consectetur adipisicing elit.`}
|
||||
</TextCustom>
|
||||
</ClickableCustom>
|
||||
</Grid.Col>
|
||||
{leftIcon && <Grid.Col span={2}>{leftIcon}</Grid.Col>}
|
||||
</Grid>
|
||||
|
||||
@@ -28,7 +28,7 @@ export async function apiInvestmentGetByStatus({
|
||||
}
|
||||
}
|
||||
|
||||
export async function apiInvestmentGetById({ id }: { id: string }) {
|
||||
export async function apiInvestmentGetOne({ id }: { id: string }) {
|
||||
try {
|
||||
const response = await apiConfig.get(`/mobile/investment/${id}`);
|
||||
return response.data;
|
||||
@@ -44,7 +44,6 @@ export async function apiInvestmentUpdateStatus({
|
||||
id: string;
|
||||
status: "publish" | "draft" | "review" | "reject";
|
||||
}) {
|
||||
|
||||
try {
|
||||
const response = await apiConfig.put(`/mobile/investment/${id}/${status}`);
|
||||
return response.data;
|
||||
@@ -71,9 +70,28 @@ export async function apiInvestmentUpdateData({
|
||||
data: any;
|
||||
category: "data" | "prospectus";
|
||||
}) {
|
||||
|
||||
try {
|
||||
const response = await apiConfig.put(`/mobile/investment/${id}?category=${category}`, {
|
||||
const response = await apiConfig.put(
|
||||
`/mobile/investment/${id}?category=${category}`,
|
||||
{
|
||||
data: data,
|
||||
}
|
||||
);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function apiInvestmentUpsertDocument({
|
||||
id,
|
||||
data,
|
||||
}: {
|
||||
id: string;
|
||||
data: any;
|
||||
}) {
|
||||
try {
|
||||
const response = await apiConfig.post(`/mobile/investment/${id}/document`, {
|
||||
data: data,
|
||||
});
|
||||
return response.data;
|
||||
@@ -81,3 +99,105 @@ export async function apiInvestmentUpdateData({
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function apiInvestmentGetDocument({
|
||||
id,
|
||||
category,
|
||||
}: {
|
||||
id: string;
|
||||
category: "one-document" | "all-document";
|
||||
}) {
|
||||
try {
|
||||
const response = await apiConfig.get(
|
||||
`/mobile/investment/${id}/document?category=${category}`
|
||||
);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function apiInvestmentDeleteDocument({ id }: { id: string }) {
|
||||
try {
|
||||
const response = await apiConfig.delete(
|
||||
`/mobile/investment/${id}/document`
|
||||
);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function apiInvestmentGetAll() {
|
||||
try {
|
||||
const response = await apiConfig.get(`/mobile/investment`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function apiInvestmentCreateInvoice({
|
||||
id,
|
||||
data,
|
||||
}: {
|
||||
id: string;
|
||||
data: any;
|
||||
}) {
|
||||
try {
|
||||
const response = await apiConfig.post(
|
||||
`/mobile/investment/${id}/invoice`,
|
||||
{
|
||||
data: data,
|
||||
}
|
||||
);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function apiInvestmentGetInvoice({
|
||||
id,
|
||||
authorId,
|
||||
category,
|
||||
}: {
|
||||
id?: string;
|
||||
authorId?: string;
|
||||
category: "my-invest" | "transaction" | "invoice";
|
||||
}) {
|
||||
const categoryQuery = `?category=${category}`;
|
||||
const authorIdQuery = authorId ? `&authorId=${authorId}` : "";
|
||||
try {
|
||||
const response = await apiConfig.get(
|
||||
`/mobile/investment/${id}/invoice${categoryQuery}${authorIdQuery}`
|
||||
);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function apiInvestmentUpdateInvoice({
|
||||
id,
|
||||
data,
|
||||
status,
|
||||
}: {
|
||||
id: string;
|
||||
data: {
|
||||
imageId?: string;
|
||||
};
|
||||
status: "berhasil" | "gagal" | "proses" | "menunggu";
|
||||
}) {
|
||||
try {
|
||||
const response = await apiConfig.put(
|
||||
`/mobile/investment/${id}/invoice?status=${status}`,
|
||||
{
|
||||
data: data,
|
||||
}
|
||||
);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,7 +110,11 @@ export async function apiForumCreateReportCommentar({
|
||||
export async function apiMasterInvestment({
|
||||
category,
|
||||
}: {
|
||||
category?: "pencarian-investor" | "periode-deviden" | "pembagian-deviden" | string;
|
||||
category?:
|
||||
| "pencarian-investor"
|
||||
| "periode-deviden"
|
||||
| "pembagian-deviden"
|
||||
| string;
|
||||
}) {
|
||||
const selectCategory = category ? `?category=${category}` : "";
|
||||
try {
|
||||
@@ -122,3 +126,12 @@ export async function apiMasterInvestment({
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function apiMasterBank() {
|
||||
try {
|
||||
const response = await apiConfig.get(`/mobile/master/bank`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user