Compare commits
10 Commits
notificati
...
notificati
| Author | SHA1 | Date | |
|---|---|---|---|
| 07e64c335e | |||
| 1aebc9b4e8 | |||
| 5665dc88ba | |||
| da82a02a45 | |||
| 14c0f0e499 | |||
| 0262423c50 | |||
| c2682246d6 | |||
| 465e01015e | |||
| 3b15871ad4 | |||
| 9123e73606 |
@@ -21,7 +21,7 @@ export default {
|
||||
"Aplikasi membutuhkan akses lokasi untuk menampilkan peta.",
|
||||
},
|
||||
associatedDomains: ["applinks:cld-dkr-staging-hipmi.wibudev.com"],
|
||||
buildNumber: "18",
|
||||
buildNumber: "20",
|
||||
},
|
||||
|
||||
android: {
|
||||
|
||||
@@ -616,6 +616,20 @@ export default function UserLayout() {
|
||||
headerLeft: () => <BackButton />,
|
||||
}}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="forum/[id]/preview-report-posting"
|
||||
options={{
|
||||
title: "Laporan Postingan",
|
||||
headerLeft: () => <BackButton />,
|
||||
}}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="forum/[id]/preview-report-comment"
|
||||
options={{
|
||||
title: "Laporan Komentar",
|
||||
headerLeft: () => <BackButton />,
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* ========== Maps Section ========= */}
|
||||
<Stack.Screen
|
||||
|
||||
@@ -9,14 +9,16 @@ import { useAuth } from "@/hooks/use-auth";
|
||||
import { dummyMasterStatus } from "@/lib/dummy-data/_master/status";
|
||||
import Donasi_BoxStatus from "@/screens/Donation/BoxStatus";
|
||||
import { apiDonationGetByStatus } from "@/service/api-client/api-donation";
|
||||
import { useFocusEffect } from "expo-router";
|
||||
import { useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import { useCallback, useState } from "react";
|
||||
|
||||
export default function DonationStatus() {
|
||||
const { user } = useAuth();
|
||||
const { status } = useLocalSearchParams<{ status?: string }>();
|
||||
|
||||
const [activeCategory, setActiveCategory] = useState<string | null>(
|
||||
"publish"
|
||||
status || "publish",
|
||||
);
|
||||
const [listData, setListData] = useState<any[] | null>(null);
|
||||
const [loadList, setLoadList] = useState(false);
|
||||
@@ -24,7 +26,7 @@ export default function DonationStatus() {
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadList();
|
||||
}, [activeCategory])
|
||||
}, [activeCategory]),
|
||||
);
|
||||
|
||||
const onLoadList = async () => {
|
||||
|
||||
@@ -16,6 +16,7 @@ import Donation_ComponentBoxDetailData from "@/screens/Donation/ComponentBoxDeta
|
||||
import Donation_ComponentStoryFunrising from "@/screens/Donation/ComponentStoryFunrising";
|
||||
import Donation_ProgressSection from "@/screens/Donation/ProgressSection";
|
||||
import { apiDonationGetOne } from "@/service/api-client/api-donation";
|
||||
import { countDownAndCondition } from "@/utils/countDownAndCondition";
|
||||
import { FontAwesome6 } from "@expo/vector-icons";
|
||||
import {
|
||||
router,
|
||||
@@ -24,7 +25,7 @@ import {
|
||||
useLocalSearchParams,
|
||||
} from "expo-router";
|
||||
import _ from "lodash";
|
||||
import { useCallback, useState } from "react";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
|
||||
export default function DonasiDetailStatus() {
|
||||
const { id, status } = useLocalSearchParams();
|
||||
@@ -58,6 +59,27 @@ export default function DonasiDetailStatus() {
|
||||
setOpenDrawer(false);
|
||||
};
|
||||
|
||||
const [value, setValue] = useState({
|
||||
sisa: 0,
|
||||
reminder: false,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
updateCountDown();
|
||||
}, [data]);
|
||||
|
||||
const updateCountDown = () => {
|
||||
const countDown = countDownAndCondition({
|
||||
duration: data?.DonasiMaster_Durasi?.name,
|
||||
publishTime: data?.publishTime,
|
||||
});
|
||||
|
||||
setValue({
|
||||
sisa: countDown.durationDay,
|
||||
reminder: countDown.reminder,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Stack.Screen
|
||||
@@ -74,10 +96,15 @@ export default function DonasiDetailStatus() {
|
||||
/>
|
||||
<ViewWrapper>
|
||||
<Donation_ComponentBoxDetailData
|
||||
sisaHari={value.sisa}
|
||||
reminder={value.reminder}
|
||||
data={data}
|
||||
bottomSection={
|
||||
status === "publish" && (
|
||||
<Donation_ProgressSection id={id as string} />
|
||||
<Donation_ProgressSection
|
||||
id={id as string}
|
||||
progres={Number(data?.progres) || 0}
|
||||
/>
|
||||
)
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -103,7 +103,7 @@ export default function DonationCreateStory() {
|
||||
type: "success",
|
||||
text1: "Donasi berhasil disimpan",
|
||||
});
|
||||
router.replace("/donation/status");
|
||||
router.replace("/donation/status?status=review");
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
|
||||
@@ -56,7 +56,7 @@ export default function EventDetailHistory() {
|
||||
<DrawerCustom
|
||||
isVisible={openDrawer}
|
||||
closeDrawer={() => setOpenDrawer(false)}
|
||||
height={250}
|
||||
height={"auto"}
|
||||
>
|
||||
<MenuDrawerDynamicGrid
|
||||
data={menuDrawerPublishEvent({ id: id as string })}
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import {
|
||||
AlertDefaultSystem,
|
||||
BackButton,
|
||||
ButtonCustom,
|
||||
DotButton,
|
||||
DrawerCustom,
|
||||
LoaderCustom,
|
||||
MenuDrawerDynamicGrid,
|
||||
ViewWrapper,
|
||||
} from "@/components";
|
||||
import { IMenuDrawerItem } from "@/components/_Interface/types";
|
||||
import CustomSkeleton from "@/components/_ShareComponent/SkeletonCustom";
|
||||
import LeftButtonCustom from "@/components/Button/BackButton";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import Event_BoxDetailPublishSection from "@/screens/Event/BoxDetailPublishSection";
|
||||
@@ -18,23 +19,26 @@ import {
|
||||
apiEventGetOne,
|
||||
apiEventJoin,
|
||||
} from "@/service/api-client/api-event";
|
||||
import dayjs from "dayjs";
|
||||
import {
|
||||
Redirect,
|
||||
router,
|
||||
Stack,
|
||||
useFocusEffect,
|
||||
useLocalSearchParams,
|
||||
} from "expo-router";
|
||||
import { useCallback, useState } from "react";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import Toast from "react-native-toast-message";
|
||||
|
||||
export default function EventDetailPublish() {
|
||||
const { id } = useLocalSearchParams();
|
||||
const now = new Date().toISOString();
|
||||
const { user } = useAuth();
|
||||
const { id } = useLocalSearchParams();
|
||||
const [openDrawer, setOpenDrawer] = useState(false);
|
||||
const [isLoadingData, setIsLoadingData] = useState(false);
|
||||
const [isLoadingJoin, setIsLoadingJoin] = useState(false);
|
||||
|
||||
const [data, setData] = useState();
|
||||
const [data, setData] = useState<any>();
|
||||
const [isParticipant, setIsParticipant] = useState<boolean | null>(null);
|
||||
|
||||
useFocusEffect(
|
||||
@@ -55,8 +59,6 @@ export default function EventDetailPublish() {
|
||||
userId: user?.id as string,
|
||||
});
|
||||
|
||||
console.log("[RES CHECK PARTICIPANTS]", responseCheckParticipants);
|
||||
|
||||
if (
|
||||
responseCheckParticipants.success &&
|
||||
responseCheckParticipants.data
|
||||
@@ -108,7 +110,24 @@ export default function EventDetailPublish() {
|
||||
}
|
||||
};
|
||||
|
||||
const footerButton = () => {
|
||||
const isEventFinished =
|
||||
id && data?.tanggalSelesai && dayjs(data.tanggalSelesai).isBefore(now);
|
||||
|
||||
useEffect(() => {
|
||||
if (isEventFinished) {
|
||||
router.replace(`/(application)/(user)/event/${id}/history`);
|
||||
}
|
||||
}, [isEventFinished, id]);
|
||||
|
||||
if (isEventFinished) {
|
||||
return (
|
||||
<ViewWrapper>
|
||||
<CustomSkeleton />
|
||||
</ViewWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
const FooterButton = () => {
|
||||
return (
|
||||
<>
|
||||
<ButtonCustom
|
||||
@@ -138,17 +157,17 @@ export default function EventDetailPublish() {
|
||||
<Stack.Screen
|
||||
options={{
|
||||
title: `Event Publish`,
|
||||
headerLeft: () => <LeftButtonCustom />,
|
||||
headerLeft: () => <BackButton onPress={() => router.back()} />,
|
||||
headerRight: () => <DotButton onPress={() => setOpenDrawer(true)} />,
|
||||
}}
|
||||
/>
|
||||
<ViewWrapper>
|
||||
{isLoadingData ? (
|
||||
<LoaderCustom />
|
||||
<CustomSkeleton height={400} />
|
||||
) : (
|
||||
<Event_BoxDetailPublishSection
|
||||
data={data}
|
||||
footerButton={footerButton()}
|
||||
footerButton={FooterButton()}
|
||||
/>
|
||||
)}
|
||||
</ViewWrapper>
|
||||
|
||||
@@ -78,23 +78,6 @@ export default function EventCreate() {
|
||||
return;
|
||||
}
|
||||
|
||||
// if (selectedDate) {
|
||||
// console.log("Tanggal yang dipilih:", selectedDate);
|
||||
// console.log(`ISO Format ${Platform.OS}:`, selectedDate.toString());
|
||||
|
||||
// // Kirim ke API atau proses lanjutan
|
||||
// } else {
|
||||
// console.log("Tanggal belum dipilih");
|
||||
// }
|
||||
|
||||
// if (selectedEndDate) {
|
||||
// console.log("Tanggal yang dipilih:", selectedEndDate);
|
||||
// console.log(`ISO Format ${Platform.OS}:`, selectedEndDate.toString());
|
||||
// // Kirim ke API atau proses lanjutan
|
||||
// } else {
|
||||
// console.log("Tanggal berakhir belum dipilih");
|
||||
// }
|
||||
|
||||
try {
|
||||
setIsLoading(true);
|
||||
|
||||
@@ -110,7 +93,7 @@ export default function EventCreate() {
|
||||
const response = await apiEventCreate(newData);
|
||||
console.log("Response", JSON.stringify(response, null, 2));
|
||||
|
||||
router.replace("/event/status");
|
||||
router.replace("/event/status?status=review");
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
} finally {
|
||||
|
||||
@@ -19,34 +19,20 @@ import {
|
||||
apiForumGetOne,
|
||||
apiForumUpdateStatus,
|
||||
} from "@/service/api-client/api-forum";
|
||||
import { TypeForum_CommentProps } from "@/types/type-forum";
|
||||
import { isBadContent } from "@/utils/badWordsIndonesia";
|
||||
import { useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { Alert } from "react-native";
|
||||
|
||||
interface CommentProps {
|
||||
id: string;
|
||||
isActive: boolean;
|
||||
komentar: string;
|
||||
createdAt: Date;
|
||||
authorId: string;
|
||||
Author: {
|
||||
id: string;
|
||||
username: string;
|
||||
Profile: {
|
||||
id: string;
|
||||
imageId: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export default function ForumDetail() {
|
||||
const { id } = useLocalSearchParams();
|
||||
const { user } = useAuth();
|
||||
const [openDrawer, setOpenDrawer] = useState(false);
|
||||
const [data, setData] = useState<any | null>(null);
|
||||
const [listComment, setListComment] = useState<CommentProps[] | null>(null);
|
||||
const [listComment, setListComment] = useState<TypeForum_CommentProps[] | null>(null);
|
||||
const [isLoadingComment, setLoadingComment] = useState(false);
|
||||
|
||||
// Status
|
||||
@@ -122,6 +108,7 @@ export default function ForumDetail() {
|
||||
comment: text,
|
||||
authorId: user?.id,
|
||||
};
|
||||
|
||||
try {
|
||||
setLoadingComment(true);
|
||||
const response = await apiForumCreateComment({
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
} from "@/components";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import { apiForumCreateReportCommentar } from "@/service/api-client/api-master";
|
||||
import { apiForumCreateReportCommentar } from "@/service/api-client/api-forum";
|
||||
import { router, useLocalSearchParams } from "expo-router";
|
||||
import { useState } from "react";
|
||||
import Toast from "react-native-toast-message";
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
} from "@/components";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import { apiForumCreateReportPosting } from "@/service/api-client/api-master";
|
||||
import { apiForumCreateReportPosting } from "@/service/api-client/api-forum";
|
||||
import { router, useLocalSearchParams } from "expo-router";
|
||||
import { useState } from "react";
|
||||
import Toast from "react-native-toast-message";
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
import {
|
||||
BaseBox,
|
||||
NewWrapper,
|
||||
Spacing,
|
||||
StackCustom,
|
||||
TextCustom,
|
||||
} from "@/components";
|
||||
import ListSkeletonComponent from "@/components/_ShareComponent/ListSkeletonComponent";
|
||||
import NoDataText from "@/components/_ShareComponent/NoDataText";
|
||||
import CustomSkeleton from "@/components/_ShareComponent/SkeletonCustom";
|
||||
import { apiForumGetReportComment } from "@/service/api-client/api-forum";
|
||||
import { useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import { useCallback, useState } from "react";
|
||||
|
||||
export default function ForumPreviewReportComment() {
|
||||
const { id } = useLocalSearchParams();
|
||||
const [data, setData] = useState<any | null>(null);
|
||||
const [listData, setListData] = useState<any | null>(null);
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
// Status
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadData(id as string);
|
||||
}, [id])
|
||||
);
|
||||
|
||||
const onLoadData = async (id: string) => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const response = await apiForumGetReportComment({ id });
|
||||
setData(response.data);
|
||||
setListData(response?.data?.Forum_ReportKomentar);
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<NewWrapper>
|
||||
<StackCustom>
|
||||
<TextCustom color="red" bold>
|
||||
Komentar anda telah melanggar aturan forum ! Admin mengambil
|
||||
tindakan untuk menghapus komentar anda!
|
||||
</TextCustom>
|
||||
{loading ? (
|
||||
<CustomSkeleton height={100} />
|
||||
) : (
|
||||
<BaseBox>
|
||||
<TextCustom>"{data?.komentar ? data?.komentar : "-"}"</TextCustom>
|
||||
</BaseBox>
|
||||
)}
|
||||
</StackCustom>
|
||||
|
||||
<Spacing height={10} />
|
||||
<TextCustom bold>Beberapa laporan yang telah diterima</TextCustom>
|
||||
<Spacing height={10} />
|
||||
|
||||
{loading ? (
|
||||
<ListSkeletonComponent />
|
||||
) : _.isEmpty(listData) ? (
|
||||
<NoDataText />
|
||||
) : (
|
||||
listData?.map((e: any, index: number) => (
|
||||
<BaseBox key={index}>
|
||||
{e?.deskripsi ? (
|
||||
<StackCustom gap={"sm"}>
|
||||
<TextCustom bold>Laporan Lainnya</TextCustom>
|
||||
<TextCustom>{e?.deskripsi}</TextCustom>
|
||||
</StackCustom>
|
||||
) : (
|
||||
<StackCustom gap={"sm"}>
|
||||
<TextCustom bold>
|
||||
{e?.ForumMaster_KategoriReport?.title}
|
||||
</TextCustom>
|
||||
<TextCustom>
|
||||
{e?.ForumMaster_KategoriReport?.deskripsi}
|
||||
</TextCustom>
|
||||
</StackCustom>
|
||||
)}
|
||||
</BaseBox>
|
||||
))
|
||||
)}
|
||||
</NewWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
import {
|
||||
BaseBox,
|
||||
NewWrapper,
|
||||
Spacing,
|
||||
StackCustom,
|
||||
TextCustom,
|
||||
} from "@/components";
|
||||
import ListSkeletonComponent from "@/components/_ShareComponent/ListSkeletonComponent";
|
||||
import NoDataText from "@/components/_ShareComponent/NoDataText";
|
||||
import CustomSkeleton from "@/components/_ShareComponent/SkeletonCustom";
|
||||
import { apiForumGetReportPosting } from "@/service/api-client/api-forum";
|
||||
import { useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import { useCallback, useState } from "react";
|
||||
|
||||
export default function ForumPreviewReportPosting() {
|
||||
const { id } = useLocalSearchParams();
|
||||
const [data, setData] = useState<any | null>(null);
|
||||
const [listData, setListData] = useState<any | null>(null);
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
// Status
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadData(id as string);
|
||||
}, [id])
|
||||
);
|
||||
|
||||
const onLoadData = async (id: string) => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const response = await apiForumGetReportPosting({ id });
|
||||
setData(response.data);
|
||||
setListData(response?.data?.Forum_ReportPosting);
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<NewWrapper>
|
||||
<StackCustom>
|
||||
<TextCustom color="red" bold>
|
||||
Postingan anda telah melanggar aturan forum ! Admin mengambil
|
||||
tindakan untuk menghapus komentar anda!
|
||||
</TextCustom>
|
||||
{loading ? (
|
||||
<CustomSkeleton height={100} />
|
||||
) : (
|
||||
<BaseBox>
|
||||
<TextCustom>"{data?.diskusi ? data?.diskusi : "-"}"</TextCustom>
|
||||
</BaseBox>
|
||||
)}
|
||||
</StackCustom>
|
||||
|
||||
<Spacing height={10} />
|
||||
<TextCustom bold>Beberapa laporan yang telah diterima</TextCustom>
|
||||
<Spacing height={10} />
|
||||
|
||||
{loading ? (
|
||||
<ListSkeletonComponent />
|
||||
) : _.isEmpty(listData) ? (
|
||||
<NoDataText />
|
||||
) : (
|
||||
listData?.map((e: any) => (
|
||||
<BaseBox key={e?.id}>
|
||||
{e?.deskripsi ? (
|
||||
<StackCustom gap={"sm"}>
|
||||
<TextCustom bold>Laporan Lainnya</TextCustom>
|
||||
<TextCustom>{e?.deskripsi}</TextCustom>
|
||||
</StackCustom>
|
||||
) : (
|
||||
<StackCustom gap={"sm"}>
|
||||
<TextCustom bold>
|
||||
{e?.ForumMaster_KategoriReport?.title}
|
||||
</TextCustom>
|
||||
<TextCustom>
|
||||
{e?.ForumMaster_KategoriReport?.deskripsi}
|
||||
</TextCustom>
|
||||
</StackCustom>
|
||||
)}
|
||||
</BaseBox>
|
||||
))
|
||||
)}
|
||||
</NewWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -8,7 +8,8 @@ import {
|
||||
import { AccentColor, MainColor } from "@/constants/color-palet";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import Forum_ReportListSection from "@/screens/Forum/ReportListSection";
|
||||
import { apiForumCreateReportCommentar, apiMasterForumReportList } from "@/service/api-client/api-master";
|
||||
import { apiForumCreateReportCommentar } from "@/service/api-client/api-forum";
|
||||
import { apiMasterForumReportList } from "@/service/api-client/api-master";
|
||||
import { router, useLocalSearchParams } from "expo-router";
|
||||
import { useState, useEffect } from "react";
|
||||
import Toast from "react-native-toast-message";
|
||||
|
||||
@@ -9,8 +9,8 @@ import {
|
||||
import { AccentColor, MainColor } from "@/constants/color-palet";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import Forum_ReportListSection from "@/screens/Forum/ReportListSection";
|
||||
import { apiForumCreateReportPosting } from "@/service/api-client/api-forum";
|
||||
import {
|
||||
apiForumCreateReportPosting,
|
||||
apiMasterForumReportList,
|
||||
} from "@/service/api-client/api-master";
|
||||
import { router, useLocalSearchParams } from "expo-router";
|
||||
|
||||
@@ -2,15 +2,14 @@ import {
|
||||
BoxButtonOnFooter,
|
||||
ButtonCustom,
|
||||
TextAreaCustom,
|
||||
ViewWrapper
|
||||
ViewWrapper,
|
||||
} from "@/components";
|
||||
import AlertWarning from "@/components/Alert/AlertWarning";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import { apiForumCreate } from "@/service/api-client/api-forum";
|
||||
import { isBadContent } from "@/utils/badWordsIndonesia";
|
||||
import { censorText, isBadContent } from "@/utils/badWordsIndonesia";
|
||||
import { router } from "expo-router";
|
||||
import { useState } from "react";
|
||||
import { Alert } from "react-native";
|
||||
import Toast from "react-native-toast-message";
|
||||
|
||||
export default function ForumCreate() {
|
||||
@@ -19,16 +18,22 @@ export default function ForumCreate() {
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const handlerSubmit = async () => {
|
||||
|
||||
if (isBadContent(text)) {
|
||||
AlertWarning({})
|
||||
if (text.trim() === "") {
|
||||
AlertWarning({
|
||||
title: "Lengkapi Data",
|
||||
description: "Postingan tidak boleh kosong",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Bisa di sensor atau return dan tidak bisa di post
|
||||
const cencorContent = censorText(text)
|
||||
|
||||
const newData = {
|
||||
diskusi: text,
|
||||
diskusi: cencorContent,
|
||||
authorId: user?.id,
|
||||
};
|
||||
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const response = await apiForumCreate({ data: newData });
|
||||
@@ -50,6 +55,7 @@ export default function ForumCreate() {
|
||||
const buttonFooter = (
|
||||
<BoxButtonOnFooter>
|
||||
<ButtonCustom
|
||||
disabled={!text.trim() || isLoading}
|
||||
isLoading={isLoading}
|
||||
onPress={() => {
|
||||
handlerSubmit();
|
||||
|
||||
@@ -1,9 +1,33 @@
|
||||
import BackButtonFromNotification from "@/components/Button/BackButtonFromNotification";
|
||||
import { ICON_SIZE_SMALL } from "@/constants/constans-value";
|
||||
import { TabsStyles } from "@/styles/tabs-styles";
|
||||
import { Feather, FontAwesome6, Ionicons } from "@expo/vector-icons";
|
||||
import { Tabs } from "expo-router";
|
||||
import { router, Tabs, useLocalSearchParams, useNavigation } from "expo-router";
|
||||
import { useLayoutEffect } from "react";
|
||||
|
||||
export default function InvestmentTabsLayout() {
|
||||
// const navigation = useNavigation();
|
||||
|
||||
// const { from, category } = useLocalSearchParams<{
|
||||
// from?: string;
|
||||
// category?: string;
|
||||
// }>();
|
||||
|
||||
// console.log("from", from);
|
||||
// console.log("category", category);
|
||||
|
||||
// // Atur header secara dinamis
|
||||
// useLayoutEffect(() => {
|
||||
// navigation.setOptions({
|
||||
// headerLeft: () => (
|
||||
// <BackButtonFromNotification
|
||||
// from={from as string}
|
||||
// category={category as string}
|
||||
// />
|
||||
// ),
|
||||
// });
|
||||
// }, [from, router, navigation]);
|
||||
|
||||
return (
|
||||
<Tabs screenOptions={TabsStyles}>
|
||||
<Tabs.Screen
|
||||
|
||||
@@ -11,9 +11,7 @@ import {
|
||||
} from "@/components";
|
||||
import NoDataText from "@/components/_ShareComponent/NoDataText";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import {
|
||||
apiInvestmentGetAll
|
||||
} from "@/service/api-client/api-investment";
|
||||
import { apiInvestmentGetAll } from "@/service/api-client/api-investment";
|
||||
import { formatCurrencyDisplay } from "@/utils/formatCurrencyDisplay";
|
||||
import { router, useFocusEffect } from "expo-router";
|
||||
import _ from "lodash";
|
||||
@@ -63,37 +61,20 @@ export default function InvestmentMyHolding() {
|
||||
router.push(`/investment/${item?.id}/(my-holding)/${item?.id}`)
|
||||
}
|
||||
>
|
||||
<Grid>
|
||||
<Grid.Col span={6}>
|
||||
<StackCustom gap={"xs"}>
|
||||
<StackCustom>
|
||||
<TextCustom truncate={2}>{item?.title}</TextCustom>
|
||||
|
||||
<Spacing height={5} />
|
||||
<TextCustom size="small">
|
||||
<TextCustom>
|
||||
Rp. {formatCurrencyDisplay(item?.nominal)}
|
||||
</TextCustom>
|
||||
<TextCustom size="small">
|
||||
{item?.lembarTerbeli} Lembar
|
||||
</TextCustom>
|
||||
</StackCustom>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={1}>
|
||||
<View />
|
||||
</Grid.Col>
|
||||
<Grid.Col
|
||||
span={5}
|
||||
style={{
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<TextCustom>{item?.lembarTerbeli} Lembar</TextCustom>
|
||||
<ProgressCustom
|
||||
value={item?.progress}
|
||||
label={`${item?.progress}%`}
|
||||
label={`${item.progress}%`}
|
||||
value={Number(item.progress)}
|
||||
size="lg"
|
||||
animated
|
||||
color="primary"
|
||||
/>
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
</StackCustom>
|
||||
</BaseBox>
|
||||
))
|
||||
)}
|
||||
|
||||
@@ -9,14 +9,16 @@ import { useAuth } from "@/hooks/use-auth";
|
||||
import { dummyMasterStatus } from "@/lib/dummy-data/_master/status";
|
||||
import Investment_StatusBox from "@/screens/Invesment/StatusBox";
|
||||
import { apiInvestmentGetByStatus } from "@/service/api-client/api-investment";
|
||||
import { useFocusEffect } from "expo-router";
|
||||
import { useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import { useCallback, useState } from "react";
|
||||
|
||||
export default function InvestmentPortofolio() {
|
||||
const { user } = useAuth();
|
||||
const { status } = useLocalSearchParams<{ status?: string }>();
|
||||
|
||||
const [activeCategory, setActiveCategory] = useState<string | null>(
|
||||
"publish"
|
||||
status || "publish"
|
||||
);
|
||||
|
||||
const [listData, setListData] = useState<any[]>([]);
|
||||
|
||||
@@ -115,7 +115,11 @@ export default function InvestmentAddNews() {
|
||||
onChangeText={(value) => setData({ ...data, deskripsi: value })}
|
||||
/>
|
||||
|
||||
<ButtonCustom isLoading={isLoading} onPress={handlerSubmit}>
|
||||
<ButtonCustom
|
||||
disabled={!data.title || !data.deskripsi || isLoading}
|
||||
isLoading={isLoading}
|
||||
onPress={handlerSubmit}
|
||||
>
|
||||
Simpan
|
||||
</ButtonCustom>
|
||||
</StackCustom>
|
||||
|
||||
@@ -27,7 +27,6 @@ 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: "",
|
||||
@@ -49,7 +48,6 @@ export default function InvestmentInvoice() {
|
||||
category: "invoice",
|
||||
});
|
||||
|
||||
console.log("[RES INVOICE]", JSON.stringify(response.data, null, 2));
|
||||
setData(response.data);
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
@@ -64,8 +62,6 @@ export default function InvestmentInvoice() {
|
||||
imageUri: image?.uri,
|
||||
});
|
||||
|
||||
console.log("[RESPONSE UPLOAD IMAGE]", responseUploadImage);
|
||||
|
||||
if (!responseUploadImage?.data?.id) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
@@ -83,10 +79,6 @@ export default function InvestmentInvoice() {
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
console.log(
|
||||
"[RESPONSE UPDATE]",
|
||||
JSON.stringify(response.data, null, 2)
|
||||
);
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: "Berhasil mengunggah bukti transfer",
|
||||
@@ -210,7 +202,6 @@ export default function InvestmentInvoice() {
|
||||
pickFile({
|
||||
allowedType: "image",
|
||||
setImageUri(file: any) {
|
||||
console.log("[IMAGE]", file);
|
||||
setImage(file);
|
||||
},
|
||||
});
|
||||
@@ -224,7 +215,7 @@ export default function InvestmentInvoice() {
|
||||
|
||||
<ButtonCustom
|
||||
isLoading={isLoading}
|
||||
disabled={!image}
|
||||
disabled={!image || isLoading}
|
||||
onPress={() => {
|
||||
handlerSubmitUpdate();
|
||||
}}
|
||||
|
||||
@@ -15,6 +15,7 @@ import Investment_ButtonInvestasiSection from "@/screens/Invesment/ButtonInvesta
|
||||
import Invesment_ComponentBoxOnBottomDetail from "@/screens/Invesment/ComponentBoxOnBottomDetail";
|
||||
import Invesment_DetailDataPublishSection from "@/screens/Invesment/DetailDataPublishSection";
|
||||
import { apiInvestmentGetOne } from "@/service/api-client/api-investment";
|
||||
import { countDownAndCondition } from "@/utils/countDownAndCondition";
|
||||
import { AntDesign, MaterialIcons } from "@expo/vector-icons";
|
||||
import {
|
||||
router,
|
||||
@@ -23,7 +24,7 @@ import {
|
||||
useLocalSearchParams,
|
||||
} from "expo-router";
|
||||
import _ from "lodash";
|
||||
import { useCallback, useState } from "react";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
|
||||
export default function InvestmentDetailStatus() {
|
||||
const { user } = useAuth();
|
||||
@@ -63,6 +64,29 @@ export default function InvestmentDetailStatus() {
|
||||
setOpenDrawerPublish(false);
|
||||
};
|
||||
|
||||
const [value, setValue] = useState({
|
||||
sisa: 0,
|
||||
reminder: false,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
updateCountDown();
|
||||
}, [data]);
|
||||
|
||||
console.log("[DATA DETAIL]", JSON.stringify(data, null, 2));
|
||||
|
||||
const updateCountDown = () => {
|
||||
const countDown = countDownAndCondition({
|
||||
duration: data?.MasterPencarianInvestor.name,
|
||||
publishTime: data?.countDown,
|
||||
});
|
||||
|
||||
setValue({
|
||||
sisa: countDown.durationDay,
|
||||
reminder: countDown.reminder,
|
||||
});
|
||||
};
|
||||
|
||||
const bottomSection = (
|
||||
<Invesment_ComponentBoxOnBottomDetail
|
||||
id={data?.id}
|
||||
@@ -72,7 +96,11 @@ export default function InvestmentDetailStatus() {
|
||||
);
|
||||
|
||||
const buttonSection = (
|
||||
<Investment_ButtonInvestasiSection id={id as string} isMine={user?.id === data?.author?.id} />
|
||||
<Investment_ButtonInvestasiSection
|
||||
id={id as string}
|
||||
isMine={user?.id === data?.author?.id}
|
||||
reminder={value.reminder}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -18,10 +18,7 @@ import {
|
||||
apiInvestmentUpdateData,
|
||||
} from "@/service/api-client/api-investment";
|
||||
import { apiMasterInvestment } from "@/service/api-client/api-master";
|
||||
import {
|
||||
deleteFileService,
|
||||
uploadFileService,
|
||||
} from "@/service/upload-service";
|
||||
import { deleteFileService, uploadFileService } from "@/service/upload-service";
|
||||
import { formatCurrencyDisplay } from "@/utils/formatCurrencyDisplay";
|
||||
import pickFile from "@/utils/pickFile";
|
||||
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
@@ -70,7 +67,7 @@ export default function InvestmentEdit() {
|
||||
useCallback(() => {
|
||||
onLoadMaster();
|
||||
onLoadData();
|
||||
}, [id])
|
||||
}, [id]),
|
||||
);
|
||||
|
||||
const onLoadMaster = async () => {
|
||||
@@ -178,7 +175,7 @@ export default function InvestmentEdit() {
|
||||
const responseUpdate = await apiInvestmentUpdateData({
|
||||
id: id as string,
|
||||
data: newData,
|
||||
category: "data"
|
||||
category: "data",
|
||||
});
|
||||
|
||||
if (responseUpdate.success) {
|
||||
@@ -256,6 +253,7 @@ export default function InvestmentEdit() {
|
||||
/>
|
||||
|
||||
<TextInputCustom
|
||||
disabled
|
||||
required
|
||||
placeholder="0"
|
||||
label="Total Lembar"
|
||||
|
||||
@@ -86,8 +86,6 @@ export default function InvestmentDetail() {
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
const bottomSection = (
|
||||
<Invesment_ComponentBoxOnBottomDetail
|
||||
id={id as string}
|
||||
@@ -97,7 +95,11 @@ export default function InvestmentDetail() {
|
||||
);
|
||||
|
||||
const buttonSection = (
|
||||
<Investment_ButtonInvestasiSection id={id as string} isMine={user?.id === data?.author?.id} reminder={value.reminder} />
|
||||
<Investment_ButtonInvestasiSection
|
||||
id={id as string}
|
||||
isMine={user?.id === data?.author?.id}
|
||||
reminder={value.reminder}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -54,7 +54,7 @@ export default function InvestmentCreate() {
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadMaster();
|
||||
}, [])
|
||||
}, []),
|
||||
);
|
||||
|
||||
const onLoadMaster = async () => {
|
||||
@@ -167,7 +167,7 @@ export default function InvestmentCreate() {
|
||||
text1: "Berhasil",
|
||||
text2: response.message,
|
||||
});
|
||||
router.replace("/investment/portofolio");
|
||||
router.replace("/investment/portofolio?status=review");
|
||||
} else {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
@@ -224,7 +224,6 @@ export default function InvestmentCreate() {
|
||||
onPress={() => {
|
||||
pickFile({
|
||||
setPdfUri: ({ uri, name, size }) => {
|
||||
|
||||
setPdf({ uri, name, size });
|
||||
},
|
||||
allowedType: "pdf",
|
||||
@@ -265,6 +264,7 @@ export default function InvestmentCreate() {
|
||||
|
||||
<StackCustom gap={0}>
|
||||
<TextInputCustom
|
||||
disabled
|
||||
required
|
||||
placeholder="0"
|
||||
label="Total Lembar"
|
||||
@@ -357,7 +357,11 @@ export default function InvestmentCreate() {
|
||||
)}
|
||||
|
||||
<Spacing />
|
||||
<ButtonCustom isLoading={isLoading} onPress={() => handleSubmit()}>
|
||||
<ButtonCustom
|
||||
disabled={isLoading}
|
||||
isLoading={isLoading}
|
||||
onPress={() => handleSubmit()}
|
||||
>
|
||||
Simpan
|
||||
</ButtonCustom>
|
||||
</StackCustom>
|
||||
|
||||
@@ -78,7 +78,7 @@ const BoxNotification = ({
|
||||
categoryApp: data.kategoriApp,
|
||||
});
|
||||
|
||||
router.replace(newPath as any);
|
||||
router.navigate(newPath as any);
|
||||
selectedCategory(activeCategory as string);
|
||||
|
||||
if (!data.isRead) {
|
||||
|
||||
@@ -36,7 +36,7 @@ export default function ProfileLayout() {
|
||||
|
||||
<Stack.Screen
|
||||
name="[id]/blocked-list"
|
||||
options={{ title: "Blocked List", headerLeft: () => <BackButton /> }}
|
||||
options={{ title: "Daftar Blokir", headerLeft: () => <BackButton /> }}
|
||||
/>
|
||||
|
||||
<Stack.Screen
|
||||
|
||||
@@ -4,10 +4,34 @@ import {
|
||||
IconHome,
|
||||
IconStatus,
|
||||
} from "@/components/_Icon";
|
||||
import BackButtonFromNotification from "@/components/Button/BackButtonFromNotification";
|
||||
import { TabsStyles } from "@/styles/tabs-styles";
|
||||
import { Tabs } from "expo-router";
|
||||
import { Tabs, useLocalSearchParams, useNavigation, router } from "expo-router";
|
||||
import { useLayoutEffect } from "react";
|
||||
|
||||
export default function VotingTabsLayout() {
|
||||
const navigation = useNavigation();
|
||||
|
||||
const { from, category } = useLocalSearchParams<{
|
||||
from?: string;
|
||||
category?: string;
|
||||
}>();
|
||||
|
||||
console.log("from", from);
|
||||
console.log("category", category);
|
||||
|
||||
// Atur header secara dinamis
|
||||
useLayoutEffect(() => {
|
||||
navigation.setOptions({
|
||||
headerLeft: () => (
|
||||
<BackButtonFromNotification
|
||||
from={from as string}
|
||||
category={category as string}
|
||||
/>
|
||||
),
|
||||
});
|
||||
}, [from, router, navigation]);
|
||||
|
||||
return (
|
||||
<Tabs screenOptions={TabsStyles}>
|
||||
<Tabs.Screen
|
||||
|
||||
@@ -12,15 +12,17 @@ import { useAuth } from "@/hooks/use-auth";
|
||||
import { dummyMasterStatus } from "@/lib/dummy-data/_master/status";
|
||||
import { apiVotingGetByStatus } from "@/service/api-client/api-voting";
|
||||
import { dateTimeView } from "@/utils/dateTimeView";
|
||||
import { useFocusEffect } from "expo-router";
|
||||
import { useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import { useCallback, useState } from "react";
|
||||
|
||||
export default function VotingStatus() {
|
||||
const { user } = useAuth();
|
||||
const { status } = useLocalSearchParams<{ status?: string }>();
|
||||
|
||||
const id = user?.id || "";
|
||||
const [activeCategory, setActiveCategory] = useState<string | null>(
|
||||
"publish"
|
||||
status || "publish"
|
||||
);
|
||||
|
||||
const [listData, setListData] = useState([]);
|
||||
@@ -86,8 +88,14 @@ export default function VotingStatus() {
|
||||
style={{ width: "70%", alignSelf: "center" }}
|
||||
variant="light"
|
||||
>
|
||||
{item?.awalVote && dateTimeView({date: item?.awalVote, withoutTime: true})} -{" "}
|
||||
{item?.akhirVote && dateTimeView({date: item?.akhirVote, withoutTime: true})}
|
||||
{item?.awalVote &&
|
||||
dateTimeView({
|
||||
date: item?.awalVote,
|
||||
withoutTime: true,
|
||||
})}{" "}
|
||||
-{" "}
|
||||
{item?.akhirVote &&
|
||||
dateTimeView({ date: item?.akhirVote, withoutTime: true })}
|
||||
</BadgeCustom>
|
||||
</StackCustom>
|
||||
</BaseBox>
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
} from "@/components";
|
||||
import { IconArchive, IconContribution } from "@/components/_Icon";
|
||||
import { IMenuDrawerItem } from "@/components/_Interface/types";
|
||||
import CustomSkeleton from "@/components/_ShareComponent/SkeletonCustom";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import Voting_BoxDetailHasilVotingSection from "@/screens/Voting/BoxDetailHasilVotingSection";
|
||||
import { Voting_BoxDetailPublishSection } from "@/screens/Voting/BoxDetailPublishSection";
|
||||
@@ -22,13 +23,14 @@ import {
|
||||
apiVotingUpdateData,
|
||||
} from "@/service/api-client/api-voting";
|
||||
import { today } from "@/utils/dateTimeView";
|
||||
import dayjs from "dayjs";
|
||||
import {
|
||||
router,
|
||||
Stack,
|
||||
useFocusEffect,
|
||||
useLocalSearchParams,
|
||||
} from "expo-router";
|
||||
import React, { useCallback, useState } from "react";
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import Toast from "react-native-toast-message";
|
||||
|
||||
export default function VotingDetail() {
|
||||
@@ -119,6 +121,23 @@ export default function VotingDetail() {
|
||||
setOpenDrawerPublish(false);
|
||||
};
|
||||
|
||||
const now = new Date().toISOString();
|
||||
const isEventFinished = id && data?.akhirVote && dayjs(data.akhirVote).isBefore(now);
|
||||
|
||||
useEffect(() => {
|
||||
if (isEventFinished) {
|
||||
router.replace(`/(application)/(user)/voting/${id}/history`);
|
||||
}
|
||||
}, [isEventFinished, id]);
|
||||
|
||||
if (isEventFinished) {
|
||||
return (
|
||||
<ViewWrapper>
|
||||
<CustomSkeleton />
|
||||
</ViewWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Stack.Screen
|
||||
|
||||
@@ -79,7 +79,7 @@ export default function VotingCreate() {
|
||||
type: "success",
|
||||
text1: "Data berhasil disimpan",
|
||||
});
|
||||
router.replace("/(application)/(user)/voting/(tabs)/status");
|
||||
router.replace("/(application)/(user)/voting/(tabs)/status?status=review");
|
||||
} else {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
AlertDefaultSystem,
|
||||
BadgeCustom,
|
||||
BaseBox,
|
||||
BoxButtonOnFooter,
|
||||
@@ -9,6 +10,7 @@ import {
|
||||
} from "@/components";
|
||||
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
|
||||
import { GridSpan_4_8 } from "@/components/_ShareComponent/GridSpan_4_8";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import {
|
||||
apiAdminDonationInvoiceDetailById,
|
||||
apiAdminDonationInvoiceUpdateById,
|
||||
@@ -22,6 +24,7 @@ import { useCallback, useState } from "react";
|
||||
import Toast from "react-native-toast-message";
|
||||
|
||||
export default function AdminDonasiTransactionDetail() {
|
||||
const { user } = useAuth();
|
||||
const { id, status } = useLocalSearchParams();
|
||||
console.log("[STATUS]", id, status);
|
||||
|
||||
@@ -33,7 +36,7 @@ export default function AdminDonasiTransactionDetail() {
|
||||
onLoadData();
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [id])
|
||||
}, [id]),
|
||||
);
|
||||
|
||||
const onLoadData = async () => {
|
||||
@@ -57,6 +60,7 @@ export default function AdminDonasiTransactionDetail() {
|
||||
const newData = {
|
||||
donationId: data?.donasiId,
|
||||
nominal: data?.nominal,
|
||||
senderId: user?.id,
|
||||
};
|
||||
|
||||
const response = await apiAdminDonationInvoiceUpdateById({
|
||||
@@ -97,7 +101,15 @@ export default function AdminDonasiTransactionDetail() {
|
||||
<ButtonCustom
|
||||
isLoading={isLoading}
|
||||
onPress={() => {
|
||||
AlertDefaultSystem({
|
||||
title: "Konfirmasi transaksi",
|
||||
message: "Apakah anda yakin ingin menyetujui transaksi ini?",
|
||||
textLeft: "Tidak",
|
||||
textRight: "Ya",
|
||||
onPressRight: () => {
|
||||
handlerSubmit();
|
||||
},
|
||||
});
|
||||
}}
|
||||
>
|
||||
Terima donasi
|
||||
@@ -140,7 +152,7 @@ export default function AdminDonasiTransactionDetail() {
|
||||
})}
|
||||
>
|
||||
{_.startCase(
|
||||
(data?.DonasiMaster_StatusInvoice?.name as any) || "-"
|
||||
(data?.DonasiMaster_StatusInvoice?.name as any) || "-",
|
||||
)}
|
||||
</BadgeCustom>
|
||||
)) ||
|
||||
@@ -157,7 +169,7 @@ export default function AdminDonasiTransactionDetail() {
|
||||
<ButtonCustom
|
||||
onPress={() =>
|
||||
router.push(
|
||||
`/(application)/(image)/preview-image/${data?.imageId}`
|
||||
`/(application)/(image)/preview-image/${data?.imageId}`,
|
||||
)
|
||||
}
|
||||
>
|
||||
|
||||
@@ -7,15 +7,15 @@ import {
|
||||
} from "@/components";
|
||||
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
|
||||
import AdminButtonReject from "@/components/_ShareComponent/Admin/ButtonReject";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import { funUpdateStatusDonation } from "@/screens/Admin/Donation/funDonationUpdateStatus";
|
||||
import {
|
||||
apiAdminDonationDetailById
|
||||
} from "@/service/api-admin/api-admin-donation";
|
||||
import { apiAdminDonationDetailById } from "@/service/api-admin/api-admin-donation";
|
||||
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import React from "react";
|
||||
import Toast from "react-native-toast-message";
|
||||
|
||||
export default function AdminDonationRejectInput() {
|
||||
const { user } = useAuth();
|
||||
const { id, status } = useLocalSearchParams();
|
||||
|
||||
const [data, setData] = React.useState<any | null>(null);
|
||||
@@ -24,7 +24,7 @@ export default function AdminDonationRejectInput() {
|
||||
useFocusEffect(
|
||||
React.useCallback(() => {
|
||||
onLoadData();
|
||||
}, [id])
|
||||
}, [id]),
|
||||
);
|
||||
|
||||
const onLoadData = async () => {
|
||||
@@ -48,11 +48,23 @@ export default function AdminDonationRejectInput() {
|
||||
changeStatus: "publish" | "review" | "reject";
|
||||
}) => {
|
||||
try {
|
||||
if (!user?.id) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: "User tidak ditemukan",
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
setIsLoading(true);
|
||||
const response = await funUpdateStatusDonation({
|
||||
id: id as string,
|
||||
changeStatus,
|
||||
data: data,
|
||||
data: {
|
||||
senderId: user?.id as string,
|
||||
catatan: data,
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.success) {
|
||||
@@ -61,7 +73,7 @@ export default function AdminDonationRejectInput() {
|
||||
text1: "Report gagal",
|
||||
});
|
||||
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
Toast.show({
|
||||
|
||||
@@ -41,8 +41,8 @@ export default function AdminEventDetail() {
|
||||
const deepLinkURL = `${DEEP_LINK_URL}/event/${id}/confirmation?userId=${user?.id}`;
|
||||
const deepLinkURLDEV = `${DEEP_LINK_URL}/--/event/${id}/confirmation?userId=${user?.id}`;
|
||||
|
||||
const isDevLink = process.env.NODE_ENV === "development" ? deepLinkURLDEV : deepLinkURL;
|
||||
|
||||
const isDevLink =
|
||||
process.env.NODE_ENV === "development" ? deepLinkURLDEV : deepLinkURL;
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
@@ -126,7 +126,7 @@ export default function AdminEventDetail() {
|
||||
const response = await funUpdateStatusEvent({
|
||||
id: id as string,
|
||||
changeStatus: "publish",
|
||||
data: {catatan: "", senderId: user?.id as string}
|
||||
data: { catatan: "", senderId: user?.id as string },
|
||||
});
|
||||
|
||||
if (!response.success) {
|
||||
|
||||
@@ -15,12 +15,11 @@ import { IconDot, IconView } from "@/components/_Icon/IconComponent";
|
||||
import { IconTrash } from "@/components/_Icon/IconTrash";
|
||||
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
|
||||
import AdminComp_BoxTitle from "@/components/_ShareComponent/Admin/BoxTitlePage";
|
||||
import AdminTitleTable from "@/components/_ShareComponent/Admin/TableTitle";
|
||||
import AdminTableValue from "@/components/_ShareComponent/Admin/TableValue";
|
||||
import { GridSpan_4_8 } from "@/components/_ShareComponent/GridSpan_4_8";
|
||||
import { GridSpan_NewComponent } from "@/components/_ShareComponent/GridSpan_NewComponent";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import { ICON_SIZE_BUTTON } from "@/constants/constans-value";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import {
|
||||
apiAdminForumCommentById,
|
||||
apiAdminForumDeactivateComment,
|
||||
@@ -35,6 +34,7 @@ import Toast from "react-native-toast-message";
|
||||
|
||||
export default function AdminForumReportComment() {
|
||||
const { id } = useLocalSearchParams();
|
||||
const { user } = useAuth();
|
||||
const [data, setData] = useState<any | null>(null);
|
||||
const [listReport, setListReport] = useState<any[] | null>(null);
|
||||
const [loadList, setLoadList] = useState(false);
|
||||
@@ -113,7 +113,11 @@ export default function AdminForumReportComment() {
|
||||
|
||||
<StackCustom gap={"sm"}>
|
||||
<GridSpan_NewComponent
|
||||
text1={<TextCustom bold align="center">Aksi</TextCustom>}
|
||||
text1={
|
||||
<TextCustom bold align="center">
|
||||
Aksi
|
||||
</TextCustom>
|
||||
}
|
||||
text2={<TextCustom bold>Pelapor</TextCustom>}
|
||||
text3={<TextCustom bold>Kategori Report</TextCustom>}
|
||||
/>
|
||||
@@ -131,7 +135,9 @@ export default function AdminForumReportComment() {
|
||||
text1={
|
||||
<CenterCustom>
|
||||
<ActionIcon
|
||||
icon={<IconView size={ICON_SIZE_BUTTON} color="black" />}
|
||||
icon={
|
||||
<IconView size={ICON_SIZE_BUTTON} color="black" />
|
||||
}
|
||||
onPress={() => {
|
||||
setOpenDrawerAction(true);
|
||||
setSelectedReport({
|
||||
@@ -188,15 +194,18 @@ export default function AdminForumReportComment() {
|
||||
onPressRight: async () => {
|
||||
const deleteComment = await apiAdminForumDeactivateComment({
|
||||
id: id as string,
|
||||
data: {
|
||||
senderId: user?.id as string,
|
||||
},
|
||||
});
|
||||
|
||||
if (!deleteComment.success) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: "Komentar gagal dihapus",
|
||||
});
|
||||
return;
|
||||
}
|
||||
// if (!deleteComment.success) {
|
||||
// Toast.show({
|
||||
// type: "error",
|
||||
// text1: "Komentar gagal dihapus",
|
||||
// });
|
||||
// return;
|
||||
// }
|
||||
|
||||
setOpenDrawer(false);
|
||||
Toast.show({
|
||||
|
||||
@@ -16,12 +16,11 @@ import { IconDot, IconView } from "@/components/_Icon/IconComponent";
|
||||
import { IconTrash } from "@/components/_Icon/IconTrash";
|
||||
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
|
||||
import AdminComp_BoxTitle from "@/components/_ShareComponent/Admin/BoxTitlePage";
|
||||
import AdminTitleTable from "@/components/_ShareComponent/Admin/TableTitle";
|
||||
import AdminTableValue from "@/components/_ShareComponent/Admin/TableValue";
|
||||
import { GridSpan_4_8 } from "@/components/_ShareComponent/GridSpan_4_8";
|
||||
import { GridSpan_NewComponent } from "@/components/_ShareComponent/GridSpan_NewComponent";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import { ICON_SIZE_BUTTON } from "@/constants/constans-value";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import {
|
||||
apiAdminForumDeactivatePosting,
|
||||
apiAdminForumListReportPostingById,
|
||||
@@ -35,6 +34,7 @@ import { Divider } from "react-native-paper";
|
||||
import Toast from "react-native-toast-message";
|
||||
|
||||
export default function AdminForumReportPosting() {
|
||||
const { user } = useAuth();
|
||||
const { id } = useLocalSearchParams();
|
||||
const [openDrawerPage, setOpenDrawerPage] = useState(false);
|
||||
const [openDrawerAction, setOpenDrawerAction] = useState(false);
|
||||
@@ -215,6 +215,9 @@ export default function AdminForumReportPosting() {
|
||||
onPressRight: async () => {
|
||||
const response = await apiAdminForumDeactivatePosting({
|
||||
id: id as string,
|
||||
data: {
|
||||
senderId: user?.id as string,
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.success) {
|
||||
|
||||
@@ -73,7 +73,7 @@ export default function AdminForumReportPosting() {
|
||||
<GridSpan_NewComponent
|
||||
text1={
|
||||
<TextCustom bold truncate>
|
||||
Username
|
||||
Pelapor
|
||||
</TextCustom>
|
||||
}
|
||||
text2={
|
||||
|
||||
@@ -20,6 +20,7 @@ import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButt
|
||||
import AdminButtonReject from "@/components/_ShareComponent/Admin/ButtonReject";
|
||||
import AdminButtonReview from "@/components/_ShareComponent/Admin/ButtonReview";
|
||||
import { GridSpan_4_8 } from "@/components/_ShareComponent/GridSpan_4_8";
|
||||
import CustomSkeleton from "@/components/_ShareComponent/SkeletonCustom";
|
||||
import ReportBox from "@/components/Box/ReportBox";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import { ICON_SIZE_BUTTON } from "@/constants/constans-value";
|
||||
@@ -28,6 +29,7 @@ import {
|
||||
apiAdminInvestmentDetailById,
|
||||
} from "@/service/api-admin/api-admin-investment";
|
||||
import { colorBadgeStatus } from "@/utils/colorBadge";
|
||||
import { countDownAndCondition } from "@/utils/countDownAndCondition";
|
||||
import { formatCurrencyDisplay } from "@/utils/formatCurrencyDisplay";
|
||||
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import _ from "lodash";
|
||||
@@ -40,91 +42,41 @@ export default function AdminInvestmentDetail() {
|
||||
|
||||
const [data, setData] = React.useState<any | null>(null);
|
||||
const [isLoading, setLoading] = React.useState(false);
|
||||
const [remind, setRemind] = React.useState({
|
||||
sisa: 0,
|
||||
reminder: false,
|
||||
});
|
||||
|
||||
useFocusEffect(
|
||||
React.useCallback(() => {
|
||||
onLoadData();
|
||||
}, [id])
|
||||
}, [id]),
|
||||
);
|
||||
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
const response = await apiAdminInvestmentDetailById({ id: id as string });
|
||||
// console.log("[GETONE INVEST]", JSON.stringify(response, null, 2));
|
||||
if (response.success) {
|
||||
setData(response.data);
|
||||
|
||||
const duration = response?.data?.MasterPencarianInvestor?.name;
|
||||
const publishTime = response?.data?.countDown;
|
||||
|
||||
const countDown = countDownAndCondition({
|
||||
duration: duration,
|
||||
publishTime: publishTime
|
||||
});
|
||||
|
||||
setRemind({
|
||||
sisa: countDown.durationDay,
|
||||
reminder: countDown.reminder,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
console.log("Error", error);
|
||||
}
|
||||
};
|
||||
|
||||
const listData = [
|
||||
{
|
||||
label: "Username",
|
||||
value: (data && data?.author?.username) || "-",
|
||||
},
|
||||
{
|
||||
label: "Judul",
|
||||
value: (data && data?.title) || "-",
|
||||
},
|
||||
{
|
||||
label: "Status",
|
||||
value:
|
||||
data && data?.MasterStatusInvestasi?.name ? (
|
||||
<BadgeCustom
|
||||
color={colorBadgeStatus({
|
||||
status: data?.MasterStatusInvestasi?.name as string,
|
||||
})}
|
||||
>
|
||||
{_.startCase(data?.MasterStatusInvestasi?.name as string)}
|
||||
</BadgeCustom>
|
||||
) : (
|
||||
"-"
|
||||
),
|
||||
},
|
||||
{
|
||||
label: "Dana Dibutuhkan",
|
||||
value: `Rp. ${
|
||||
(data && data?.targetDana && formatCurrencyDisplay(data?.targetDana)) ||
|
||||
"-"
|
||||
}`,
|
||||
},
|
||||
{
|
||||
label: "Harga Perlembar",
|
||||
value: `Rp. ${
|
||||
(data &&
|
||||
data?.hargaLembar &&
|
||||
formatCurrencyDisplay(data?.hargaLembar)) ||
|
||||
"-"
|
||||
}`,
|
||||
},
|
||||
{
|
||||
label: "Total Lembar",
|
||||
value:
|
||||
(data &&
|
||||
data?.totalLembar &&
|
||||
formatCurrencyDisplay(data?.totalLembar)) ||
|
||||
"-",
|
||||
},
|
||||
{
|
||||
label: "ROI",
|
||||
value: `${(data && data?.roi && data?.roi) || 0} %`,
|
||||
},
|
||||
{
|
||||
label: "Pembagian Deviden",
|
||||
value: (data && data?.MasterPembagianDeviden?.name) + " bulan" || "-",
|
||||
},
|
||||
{
|
||||
label: "Jadwal Pembagian",
|
||||
value: (data && data?.MasterPeriodeDeviden?.name) || "-",
|
||||
},
|
||||
{
|
||||
label: "Pencarian Investor",
|
||||
value: (data && data?.MasterPencarianInvestor?.name) + " hari" || "-",
|
||||
},
|
||||
];
|
||||
|
||||
const handlerSubmitPublish = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
@@ -134,7 +86,6 @@ export default function AdminInvestmentDetail() {
|
||||
data: data,
|
||||
});
|
||||
|
||||
// console.log("[GET ON INVEST]", JSON.stringify(response, null, 2));
|
||||
if (!response.success) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
@@ -164,6 +115,16 @@ export default function AdminInvestmentDetail() {
|
||||
/>
|
||||
);
|
||||
|
||||
if (!data) {
|
||||
return (
|
||||
<>
|
||||
<ViewWrapper>
|
||||
<CustomSkeleton height={200} />
|
||||
</ViewWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<ViewWrapper
|
||||
@@ -177,8 +138,8 @@ export default function AdminInvestmentDetail() {
|
||||
{status === "publish" && (
|
||||
<BaseBox>
|
||||
<ProgressCustom
|
||||
label={data && `${data.progress}%` || "0%"}
|
||||
value={data && data.progress || 0}
|
||||
label={(data && `${data.progress}%`) || "0%"}
|
||||
value={(data && data.progress) || 0}
|
||||
size="lg"
|
||||
/>
|
||||
<Spacing />
|
||||
@@ -187,7 +148,8 @@ export default function AdminInvestmentDetail() {
|
||||
label={<TextCustom bold>Sisa Saham</TextCustom>}
|
||||
value={
|
||||
<TextCustom>
|
||||
{data && formatCurrencyDisplay(data && data?.sisaLembar)} lembar
|
||||
{data && formatCurrencyDisplay(data && data?.sisaLembar)}{" "}
|
||||
lembar
|
||||
</TextCustom>
|
||||
}
|
||||
/>
|
||||
@@ -206,13 +168,15 @@ export default function AdminInvestmentDetail() {
|
||||
<BaseBox>
|
||||
<StackCustom>
|
||||
<DummyLandscapeImage imageId={data?.imageId} />
|
||||
{listData.map((item, i) => (
|
||||
{listData({ data: data, reminder: remind.reminder })?.map(
|
||||
(item, i) => (
|
||||
<GridSpan_4_8
|
||||
key={i}
|
||||
label={<TextCustom bold>{item.label}</TextCustom>}
|
||||
value={<TextCustom>{item.value}</TextCustom>}
|
||||
/>
|
||||
))}
|
||||
),
|
||||
)}
|
||||
</StackCustom>
|
||||
</BaseBox>
|
||||
|
||||
@@ -230,7 +194,7 @@ export default function AdminInvestmentDetail() {
|
||||
}
|
||||
onPress={() => {
|
||||
router.push(
|
||||
`/(application)/(file)/${data?.prospektusFileId}`
|
||||
`/(application)/(file)/${data?.prospektusFileId}`,
|
||||
);
|
||||
}}
|
||||
>
|
||||
@@ -259,7 +223,7 @@ export default function AdminInvestmentDetail() {
|
||||
}
|
||||
onPress={() => {
|
||||
router.push(
|
||||
`/(application)/(file)/${item?.fileId}`
|
||||
`/(application)/(file)/${item?.fileId}`,
|
||||
);
|
||||
}}
|
||||
>
|
||||
@@ -299,8 +263,8 @@ export default function AdminInvestmentDetail() {
|
||||
onReject={() => {
|
||||
router.push(
|
||||
`/admin/investment/${id}/reject-input?status=${_.lowerCase(
|
||||
data?.MasterStatusInvestasi?.name
|
||||
)}`
|
||||
data?.MasterStatusInvestasi?.name,
|
||||
)}`,
|
||||
);
|
||||
}}
|
||||
/>
|
||||
@@ -343,3 +307,67 @@ export default function AdminInvestmentDetail() {
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const listData = ({ data, reminder }: { data: any; reminder: boolean }) => [
|
||||
{
|
||||
label: "Username",
|
||||
value: (data && data?.author?.username) || "-",
|
||||
},
|
||||
{
|
||||
label: "Judul",
|
||||
value: (data && data?.title) || "-",
|
||||
},
|
||||
{
|
||||
label: "Status",
|
||||
value:
|
||||
data && data?.MasterStatusInvestasi?.name ? (
|
||||
<BadgeCustom
|
||||
color={colorBadgeStatus({
|
||||
status: reminder ? "periode berakhir" : "publish",
|
||||
})}
|
||||
>
|
||||
{reminder
|
||||
? "Periode Berakhir"
|
||||
: _.startCase(data?.MasterStatusInvestasi?.name as string)}
|
||||
</BadgeCustom>
|
||||
) : (
|
||||
"-"
|
||||
),
|
||||
},
|
||||
{
|
||||
label: "Dana Dibutuhkan",
|
||||
value: `Rp. ${
|
||||
(data && data?.targetDana && formatCurrencyDisplay(data?.targetDana)) ||
|
||||
"-"
|
||||
}`,
|
||||
},
|
||||
{
|
||||
label: "Harga Perlembar",
|
||||
value: `Rp. ${
|
||||
(data && data?.hargaLembar && formatCurrencyDisplay(data?.hargaLembar)) ||
|
||||
"-"
|
||||
}`,
|
||||
},
|
||||
{
|
||||
label: "Total Lembar",
|
||||
value:
|
||||
(data && data?.totalLembar && formatCurrencyDisplay(data?.totalLembar)) ||
|
||||
"-",
|
||||
},
|
||||
{
|
||||
label: "ROI",
|
||||
value: `${(data && data?.roi && data?.roi) || 0} %`,
|
||||
},
|
||||
{
|
||||
label: "Pembagian Deviden",
|
||||
value: (data && data?.MasterPembagianDeviden?.name) + " bulan" || "-",
|
||||
},
|
||||
{
|
||||
label: "Jadwal Pembagian",
|
||||
value: (data && data?.MasterPeriodeDeviden?.name) || "-",
|
||||
},
|
||||
{
|
||||
label: "Pencarian Investor",
|
||||
value: (data && data?.MasterPencarianInvestor?.name) + " hari" || "-",
|
||||
},
|
||||
];
|
||||
|
||||
@@ -13,6 +13,7 @@ import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButt
|
||||
import { GridSpan_4_8 } from "@/components/_ShareComponent/GridSpan_4_8";
|
||||
import GridTwoView from "@/components/_ShareComponent/GridTwoView";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import {
|
||||
apiAdminInvestmentGetOneInvoiceById,
|
||||
apiAdminInvestmentUpdateInvoice,
|
||||
@@ -25,6 +26,7 @@ import { useCallback, useState } from "react";
|
||||
import Toast from "react-native-toast-message";
|
||||
|
||||
export default function AdminInvestmentTransactionDetail() {
|
||||
const { user } = useAuth();
|
||||
const { id } = useLocalSearchParams();
|
||||
const [data, setData] = useState<any | null>(null);
|
||||
const [isLoading, setLoading] = useState<boolean>(false);
|
||||
@@ -32,7 +34,7 @@ export default function AdminInvestmentTransactionDetail() {
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadData();
|
||||
}, [id])
|
||||
}, [id]),
|
||||
);
|
||||
|
||||
const onLoadData = async () => {
|
||||
@@ -40,7 +42,6 @@ export default function AdminInvestmentTransactionDetail() {
|
||||
const response = await apiAdminInvestmentGetOneInvoiceById({
|
||||
id: id as string,
|
||||
});
|
||||
// console.log("[RESPONSE]", JSON.stringify(response, null, 2));
|
||||
if (response.success) {
|
||||
setData(response.data);
|
||||
}
|
||||
@@ -92,7 +93,7 @@ export default function AdminInvestmentTransactionDetail() {
|
||||
<ButtonCustom
|
||||
onPress={() =>
|
||||
router.push(
|
||||
`/(application)/(image)/preview-image/${data?.imageId}`
|
||||
`/(application)/(image)/preview-image/${data?.imageId}`,
|
||||
)
|
||||
}
|
||||
>
|
||||
@@ -109,6 +110,13 @@ export default function AdminInvestmentTransactionDetail() {
|
||||
}: {
|
||||
category: "accept" | "deny";
|
||||
}) => {
|
||||
if (!user?.id) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: "Gagal update status transaksi",
|
||||
});
|
||||
return;
|
||||
}
|
||||
try {
|
||||
setLoading(true);
|
||||
const response = await apiAdminInvestmentUpdateInvoice({
|
||||
@@ -117,11 +125,10 @@ export default function AdminInvestmentTransactionDetail() {
|
||||
data: {
|
||||
investasiId: data?.investasiId,
|
||||
lembarTerbeli: data?.lembarTerbeli,
|
||||
senderId: user?.id as any,
|
||||
},
|
||||
});
|
||||
|
||||
// console.log("[RESPONSE SUBMIT]", JSON.stringify(response, null, 2));
|
||||
|
||||
if (!response.success) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
@@ -153,6 +160,7 @@ export default function AdminInvestmentTransactionDetail() {
|
||||
styleRight={{ paddingLeft: 10 }}
|
||||
leftIcon={
|
||||
<ButtonCustom
|
||||
disabled={isLoading}
|
||||
isLoading={isLoading}
|
||||
backgroundColor={MainColor.red}
|
||||
textColor="white"
|
||||
@@ -175,6 +183,7 @@ export default function AdminInvestmentTransactionDetail() {
|
||||
}
|
||||
rightIcon={
|
||||
<ButtonCustom
|
||||
disabled={isLoading}
|
||||
isLoading={isLoading}
|
||||
onPress={() => {
|
||||
AlertDefaultSystem({
|
||||
@@ -198,8 +207,8 @@ export default function AdminInvestmentTransactionDetail() {
|
||||
} else if (data?.StatusInvoice?.name === "Gagal") {
|
||||
return (
|
||||
<>
|
||||
<ButtonCustom textColor="red" onPress={() => router.back()}>
|
||||
Gagal
|
||||
<ButtonCustom disabled onPress={() => router.back()}>
|
||||
Transaksi telah gagal
|
||||
</ButtonCustom>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -7,16 +7,21 @@ import {
|
||||
} from "@/components";
|
||||
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
|
||||
import AdminButtonReject from "@/components/_ShareComponent/Admin/ButtonReject";
|
||||
import { apiAdminInvestasiUpdateByStatus, apiAdminInvestmentDetailById } from "@/service/api-admin/api-admin-investment";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import {
|
||||
apiAdminInvestasiUpdateByStatus,
|
||||
apiAdminInvestmentDetailById,
|
||||
} from "@/service/api-admin/api-admin-investment";
|
||||
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import { useCallback, useState } from "react";
|
||||
import Toast from "react-native-toast-message";
|
||||
|
||||
export default function AdminInvestmentRejectInput() {
|
||||
const { user } = useAuth();
|
||||
const { id, status } = useLocalSearchParams();
|
||||
console.log("[STATUS]", status);
|
||||
const [value, setValue] = useState<any | null>(null);
|
||||
const [isLoading , setLoading] = useState(false)
|
||||
const [isLoading, setLoading] = useState(false);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
@@ -45,12 +50,23 @@ export default function AdminInvestmentRejectInput() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!user?.id) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: "User tidak ditemukan",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
setLoading(true)
|
||||
setLoading(true);
|
||||
const response = await apiAdminInvestasiUpdateByStatus({
|
||||
id: id as string,
|
||||
status: "reject",
|
||||
data: value,
|
||||
data: {
|
||||
catatan: value,
|
||||
senderId: user?.id as string,
|
||||
},
|
||||
});
|
||||
|
||||
console.log("[RESPONSE]", JSON.stringify(response, null, 2));
|
||||
@@ -76,7 +92,7 @@ export default function AdminInvestmentRejectInput() {
|
||||
} catch (error) {
|
||||
console.error(["ERROR"], error);
|
||||
} finally {
|
||||
setLoading(false)
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -22,8 +22,6 @@ import { Divider } from "react-native-paper";
|
||||
|
||||
export default function AdminInvestmentStatus() {
|
||||
const { status } = useLocalSearchParams();
|
||||
console.log("[STATUS]", status);
|
||||
|
||||
const [listData, setListData] = React.useState<any[] | null>(null);
|
||||
const [loadData, setLoadingData] = React.useState(false);
|
||||
const [search, setSearch] = React.useState("");
|
||||
@@ -41,7 +39,7 @@ export default function AdminInvestmentStatus() {
|
||||
category: status as "publish" | "review" | "reject",
|
||||
search,
|
||||
});
|
||||
console.log("[LIST DATA]", JSON.stringify(response, null, 2));
|
||||
|
||||
if (response.success) {
|
||||
setListData(response.data);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import AdminButtonReview from "@/components/_ShareComponent/Admin/ButtonReview";
|
||||
import { GridSpan_4_8 } from "@/components/_ShareComponent/GridSpan_4_8";
|
||||
import ReportBox from "@/components/Box/ReportBox";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import funUpdateStatusVoting from "@/screens/Admin/Voting/funUpdateStatus";
|
||||
import { apiAdminVotingById } from "@/service/api-admin/api-admin-voting";
|
||||
import { colorBadgeStatus } from "@/utils/colorBadge";
|
||||
@@ -29,6 +30,7 @@ import { List } from "react-native-paper";
|
||||
import Toast from "react-native-toast-message";
|
||||
|
||||
export default function AdminVotingDetail() {
|
||||
const { user } = useAuth();
|
||||
const { id, status } = useLocalSearchParams();
|
||||
const [data, setData] = useState<any | null>(null);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
@@ -139,6 +141,10 @@ export default function AdminVotingDetail() {
|
||||
const response = await funUpdateStatusVoting({
|
||||
id: id as string,
|
||||
changeStatus,
|
||||
data: {
|
||||
senderId: user?.id as string,
|
||||
catatan: "",
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.success) {
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
} from "@/components";
|
||||
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
|
||||
import AdminButtonReject from "@/components/_ShareComponent/Admin/ButtonReject";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import funUpdateStatusVoting from "@/screens/Admin/Voting/funUpdateStatus";
|
||||
import { apiAdminVotingById } from "@/service/api-admin/api-admin-voting";
|
||||
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
@@ -14,6 +15,7 @@ import { useCallback, useState } from "react";
|
||||
import Toast from "react-native-toast-message";
|
||||
|
||||
export default function AdminVotingRejectInput() {
|
||||
const { user } = useAuth()
|
||||
const { id, status } = useLocalSearchParams();
|
||||
const [data, setData] = useState("");
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
@@ -48,7 +50,10 @@ export default function AdminVotingRejectInput() {
|
||||
const response = await funUpdateStatusVoting({
|
||||
id: id as string,
|
||||
changeStatus,
|
||||
data: data,
|
||||
data: {
|
||||
catatan: data,
|
||||
senderId: user?.id as string,
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.success) {
|
||||
|
||||
@@ -24,8 +24,6 @@ const DateTimePickerCustom: React.FC<Props> = ({
|
||||
disabled = false,
|
||||
}) => {
|
||||
|
||||
console.log("Date Android Comp", value)
|
||||
|
||||
return (
|
||||
<>
|
||||
{Platform.OS === "ios" ? (
|
||||
|
||||
33
components/Modal/ModalReactNative.tsx
Normal file
33
components/Modal/ModalReactNative.tsx
Normal file
@@ -0,0 +1,33 @@
|
||||
import { Modal, View } from "react-native";
|
||||
|
||||
export default function ModalReactNative({
|
||||
children,
|
||||
isVisible,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
isVisible: boolean;
|
||||
}) {
|
||||
return (
|
||||
<Modal
|
||||
animationType="slide"
|
||||
backdropColor={"rgba(0, 0, 0, 0.5)"}
|
||||
visible={isVisible}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
flex: 1,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
backgroundColor: "rgba(0, 0, 0, 0.5)",
|
||||
// margin: 10,
|
||||
marginBlock: 30,
|
||||
padding: 10,
|
||||
borderRadius: 10,
|
||||
paddingTop: 30
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</View>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
@@ -21,7 +21,7 @@ type AuthContextType = {
|
||||
isAuthenticated: boolean;
|
||||
isAdmin: boolean;
|
||||
isUserActive: boolean;
|
||||
loginWithNomor: (nomor: string) => Promise<void>;
|
||||
loginWithNomor: (nomor: string) => Promise<boolean>;
|
||||
validateOtp: (nomor: string) => Promise<any>;
|
||||
logout: () => Promise<void>;
|
||||
registerUser: (userData: {
|
||||
@@ -30,12 +30,12 @@ type AuthContextType = {
|
||||
termsOfServiceAccepted: boolean;
|
||||
}) => Promise<void>;
|
||||
userData: (token: string) => Promise<any>;
|
||||
acceptedTerms: (nomor: string) => Promise<any>;
|
||||
acceptedTerms: (nomor: string, onSetModalVisible: (visible: boolean) => void) => Promise<any>;
|
||||
};
|
||||
|
||||
// --- Create Context ---
|
||||
export const AuthContext = createContext<AuthContextType | undefined>(
|
||||
undefined
|
||||
undefined,
|
||||
);
|
||||
|
||||
export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
|
||||
@@ -79,31 +79,35 @@ export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
|
||||
const response = await apiLogin({ nomor: nomor });
|
||||
console.log("[RESPONSE AUTH]", JSON.stringify(response, null, 2));
|
||||
|
||||
if (response.success) {
|
||||
if (response.isAcceptTerms) {
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: "Sukses",
|
||||
text2: "Kode OTP berhasil dikirim",
|
||||
});
|
||||
if (response.success && response.isAcceptTerms) {
|
||||
|
||||
await AsyncStorage.setItem("kode_otp", response.kodeId);
|
||||
router.push(`/verification?nomor=${nomor}`);
|
||||
return;
|
||||
return true;
|
||||
} else {
|
||||
router.push(`/eula?nomor=${nomor}`);
|
||||
return;
|
||||
// router.push(`/eula?nomor=${nomor}`);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
router.push(`/eula?nomor=${nomor}`);
|
||||
|
||||
// if (response.success) {
|
||||
// if (response.isAcceptTerms) {
|
||||
// Toast.show({
|
||||
// type: "info",
|
||||
// text1: "Info",
|
||||
// text2: "Silahkan mendaftar",
|
||||
// type: "success",
|
||||
// text1: "Sukses",
|
||||
// text2: "Kode OTP berhasil dikirim",
|
||||
// });
|
||||
return;
|
||||
}
|
||||
|
||||
// await AsyncStorage.setItem("kode_otp", response.kodeId);
|
||||
// router.push(`/verification?nomor=${nomor}`);
|
||||
// return false
|
||||
// } else {
|
||||
// // router.push(`/eula?nomor=${nomor}`);
|
||||
// return true
|
||||
// }
|
||||
// } else {
|
||||
// router.push(`/eula?nomor=${nomor}`);
|
||||
// return true;
|
||||
// }
|
||||
} catch (error: any) {
|
||||
throw new Error(error.response?.data?.message || "Gagal kirim OTP");
|
||||
} finally {
|
||||
@@ -158,7 +162,7 @@ export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
|
||||
} catch (error: any) {
|
||||
console.log("Error validasi otp >>", (error as Error).message || error);
|
||||
throw new Error(
|
||||
error.response?.data?.message || "OTP salah atau user tidak ditemukan"
|
||||
error.response?.data?.message || "OTP salah atau user tidak ditemukan",
|
||||
);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
@@ -187,7 +191,7 @@ export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
|
||||
} catch (error: any) {
|
||||
console.log(
|
||||
"[LOAD USER DATA]",
|
||||
error.response?.data?.message + "user" || "Gagal mengambil data user"
|
||||
error.response?.data?.message + "user" || "Gagal mengambil data user",
|
||||
);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
@@ -261,7 +265,8 @@ export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
|
||||
}
|
||||
};
|
||||
|
||||
const acceptedTerms = async (nomor: string) => {
|
||||
// --- 6. Accept Terms ---
|
||||
const acceptedTerms = async (nomor: string, onSetModalVisible: (visible: boolean) => void) => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const response = await apiUpdatedTermCondition({ nomor: nomor });
|
||||
@@ -283,6 +288,7 @@ export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
|
||||
console.log("Error accept terms", error);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
// onSetModalVisible(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ android: bunx expo prebuild --platform android
|
||||
adb devices : cek device yang terhubung
|
||||
Note: izinkan perangkat dulu agar statusnya tidak unauthorized
|
||||
|
||||
adb install android/app/build/outputs/apk/debug/app-debug.apk : install apk ke device
|
||||
adb install android/app/build/outputs/apk/debug/app-debug.apk : install apk ke device / emulator
|
||||
Note:
|
||||
Gunakan flag -s (serial) di perintah adb untuk menentukan target
|
||||
adb -s <0G52319V261040B2 ini adalah id nya> install android/app/build/outputs/apk/debug/app-debug.apk
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>18</string>
|
||||
<string>20</string>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { apiAdminDonationUpdateStatus } from "@/service/api-admin/api-admin-donation";
|
||||
import { typeRejectedData } from "@/types/type-collect-other";
|
||||
|
||||
export const funUpdateStatusDonation = async ({
|
||||
id,
|
||||
@@ -7,7 +8,7 @@ export const funUpdateStatusDonation = async ({
|
||||
}: {
|
||||
id: string;
|
||||
changeStatus: "publish" | "review" | "reject";
|
||||
data?: string;
|
||||
data?: typeRejectedData;
|
||||
}) => {
|
||||
try {
|
||||
const response = await apiAdminDonationUpdateStatus({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { apiAdminEventUpdateStatus } from "@/service/api-admin/api-admin-event";
|
||||
import { RejectedData } from "@/types/type-collect-other";
|
||||
import { typeRejectedData } from "@/types/type-collect-other";
|
||||
|
||||
export const funUpdateStatusEvent = async ({
|
||||
id,
|
||||
@@ -8,7 +8,7 @@ export const funUpdateStatusEvent = async ({
|
||||
}: {
|
||||
id: string;
|
||||
changeStatus: "publish" | "review" | "reject";
|
||||
data?: RejectedData;
|
||||
data?: typeRejectedData;
|
||||
}) => {
|
||||
try {
|
||||
console.log("[DATA]", data);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { apiAdminVotingUpdateStatus } from "@/service/api-admin/api-admin-voting";
|
||||
import { typeRejectedData } from "@/types/type-collect-other";
|
||||
|
||||
const funUpdateStatusVoting = async ({
|
||||
id,
|
||||
@@ -7,7 +8,7 @@ const funUpdateStatusVoting = async ({
|
||||
}: {
|
||||
id: string;
|
||||
changeStatus: "publish" | "review" | "reject";
|
||||
data?: string;
|
||||
data?: typeRejectedData;
|
||||
}) => {
|
||||
try {
|
||||
const response = await apiAdminVotingUpdateStatus({
|
||||
|
||||
264
screens/Authentication/EULASection.tsx
Normal file
264
screens/Authentication/EULASection.tsx
Normal file
@@ -0,0 +1,264 @@
|
||||
// app/syarat-dan-ketentuan.tsx
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
ScrollView,
|
||||
TouchableOpacity,
|
||||
StyleSheet,
|
||||
} from "react-native";
|
||||
import { useState, useRef } from "react";
|
||||
import { useLocalSearchParams, useRouter } from "expo-router";
|
||||
import { SafeAreaView } from "react-native-safe-area-context";
|
||||
import { AccentColor, MainColor } from "@/constants/color-palet";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
|
||||
|
||||
export default function EULASection({ nomor, onSetModalVisible }: { nomor: string, onSetModalVisible: (visible: boolean) => void }) {
|
||||
const { acceptedTerms } = useAuth();
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
const [isAtBottom, setIsAtBottom] = useState(false);
|
||||
const scrollViewRef = useRef<ScrollView>(null);
|
||||
|
||||
const handleScroll = (event: any) => {
|
||||
const { layoutMeasurement, contentOffset, contentSize } = event.nativeEvent;
|
||||
const paddingToBottom = 20;
|
||||
const isCloseToBottom =
|
||||
layoutMeasurement.height + contentOffset.y >=
|
||||
contentSize.height - paddingToBottom;
|
||||
setIsAtBottom(isCloseToBottom);
|
||||
};
|
||||
|
||||
const handleAccept = async () => {
|
||||
// console.log("Accept terms", nomor);
|
||||
// onSetModalVisible(false);
|
||||
try {
|
||||
if (!isAtBottom) return;
|
||||
|
||||
setIsLoading(true);
|
||||
await acceptedTerms(nomor as string, onSetModalVisible);
|
||||
} catch (error) {
|
||||
console.log("Error accept terms", error);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<SafeAreaView edges={["bottom"]} style={styles.container}>
|
||||
<Text style={styles.title}>
|
||||
Syarat & Ketentuan Penggunaan HIPMI Badung Connect
|
||||
</Text>
|
||||
|
||||
<ScrollView
|
||||
ref={scrollViewRef}
|
||||
onScroll={handleScroll}
|
||||
scrollEventThrottle={16}
|
||||
style={styles.scrollView}
|
||||
contentContainerStyle={styles.scrollContent}
|
||||
>
|
||||
<Text style={styles.paragraph}>
|
||||
Dengan menggunakan aplikasi{" "}
|
||||
<Text style={styles.bold}>HIPMI Badung Connect</Text> (“Aplikasi”),
|
||||
Anda setuju untuk mematuhi dan terikat oleh syarat dan ketentuan
|
||||
berikut. Jika Anda tidak setuju dengan ketentuan ini, harap jangan
|
||||
gunakan Aplikasi.
|
||||
</Text>
|
||||
|
||||
<Text style={styles.heading}>1. Definisi</Text>
|
||||
<Text style={styles.paragraph}>
|
||||
<Text style={styles.bold}>HIPMI Badung Connect</Text> adalah platform
|
||||
digital resmi untuk anggota Himpunan Pengusaha Muda Indonesia (HIPMI)
|
||||
Kabupaten Badung, yang bertujuan memfasilitasi jaringan, kolaborasi,
|
||||
dan pertumbuhan bisnis para pengusaha muda.
|
||||
</Text>
|
||||
|
||||
<Text style={styles.heading}>2. Larangan Konten Tidak Pantas</Text>
|
||||
<Text style={styles.paragraph}>
|
||||
Anda <Text style={styles.bold}>dilarang keras</Text> memposting,
|
||||
mengirim, membagikan, atau mengunggah konten apa pun yang mengandung:
|
||||
</Text>
|
||||
<View style={styles.list}>
|
||||
<Text style={styles.listItem}>
|
||||
• Ujaran kebencian, diskriminasi, atau konten SARA (Suku, Agama,
|
||||
Ras, Antar-golongan)
|
||||
</Text>
|
||||
<Text style={styles.listItem}>
|
||||
• Pornografi, konten seksual eksplisit, atau gambar tidak senonoh
|
||||
</Text>
|
||||
<Text style={styles.listItem}>
|
||||
• Ancaman, pelecehan, bullying, atau perilaku melecehkan
|
||||
</Text>
|
||||
<Text style={styles.listItem}>
|
||||
• Informasi palsu, hoaks, spam, atau konten menyesatkan
|
||||
</Text>
|
||||
<Text style={styles.listItem}>
|
||||
• Konten ilegal, melanggar hukum, atau melanggar hak kekayaan
|
||||
intelektual pihak lain
|
||||
</Text>
|
||||
<Text style={styles.listItem}>
|
||||
• Promosi narkoba, perjudian, atau aktivitas ilegal lainnya
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<Text style={styles.heading}>3. Tanggung Jawab Pengguna</Text>
|
||||
<Text style={styles.paragraph}>
|
||||
Anda bertanggung jawab penuh atas setiap konten yang Anda unggah atau
|
||||
bagikan melalui fitur-fitur berikut:
|
||||
</Text>
|
||||
<View style={styles.list}>
|
||||
<Text style={styles.listItem}>• Profil (bio, foto, portofolio)</Text>
|
||||
<Text style={styles.listItem}>• Forum diskusi</Text>
|
||||
<Text style={styles.listItem}>• Chat pribadi atau grup</Text>
|
||||
<Text style={styles.listItem}>
|
||||
• Lowongan kerja, investasi, dan donasi
|
||||
</Text>
|
||||
</View>
|
||||
<Text style={styles.paragraph}>
|
||||
Konten yang melanggar ketentuan ini dapat dihapus kapan saja tanpa
|
||||
pemberitahuan.
|
||||
</Text>
|
||||
|
||||
<Text style={styles.heading}>4. Tindakan terhadap Pelanggaran</Text>
|
||||
<Text style={styles.paragraph}>
|
||||
Jika kami menerima laporan atau menemukan konten yang melanggar
|
||||
ketentuan ini, kami akan:
|
||||
</Text>
|
||||
<View style={styles.list}>
|
||||
<Text style={styles.listItem}>
|
||||
• Segera menghapus konten tersebut
|
||||
</Text>
|
||||
<Text style={styles.listItem}>
|
||||
• Memberikan peringatan atau memblokir akun pengguna
|
||||
</Text>
|
||||
<Text style={styles.listItem}>
|
||||
• Dalam kasus berat, melaporkan ke pihak berwajib sesuai hukum yang
|
||||
berlaku
|
||||
</Text>
|
||||
</View>
|
||||
<Text style={styles.paragraph}>
|
||||
Tim kami berkomitmen untuk menanggapi laporan konten tidak pantas{" "}
|
||||
<Text style={styles.bold}>dalam waktu 24 jam</Text>.
|
||||
</Text>
|
||||
|
||||
<Text style={styles.heading}>5. Mekanisme Pelaporan</Text>
|
||||
<Text style={styles.paragraph}>
|
||||
Anda dapat melaporkan konten atau pengguna yang mencurigakan melalui:
|
||||
</Text>
|
||||
<View style={styles.list}>
|
||||
<Text style={styles.listItem}>
|
||||
• Tombol <Text style={styles.bold}>“Laporkan”</Text> di setiap
|
||||
posting forum atau pesan chat
|
||||
</Text>
|
||||
<Text style={styles.listItem}>
|
||||
• Tombol <Text style={styles.bold}>“Blokir Pengguna”</Text> di
|
||||
profil pengguna
|
||||
</Text>
|
||||
</View>
|
||||
<Text style={styles.paragraph}>
|
||||
Setiap laporan akan ditangani secara rahasia dan segera.
|
||||
</Text>
|
||||
|
||||
<Text style={styles.heading}>6. Perubahan Ketentuan</Text>
|
||||
<Text style={styles.paragraph}>
|
||||
Kami berhak memperbarui Syarat & Ketentuan ini sewaktu-waktu. Versi
|
||||
terbaru akan dipublikasikan di halaman ini dengan tanggal revisi yang
|
||||
diperbarui.
|
||||
</Text>
|
||||
|
||||
<Text style={styles.heading}>7. Kontak</Text>
|
||||
<Text style={styles.paragraph}>
|
||||
Jika Anda memiliki pertanyaan tentang ketentuan ini, silakan hubungi
|
||||
kami di:{"\n"}
|
||||
<Text style={[styles.bold, { color: "#1E90FF" }]}>
|
||||
bip.baliinteraktifperkasa@gmail.com
|
||||
</Text>
|
||||
</Text>
|
||||
|
||||
<Text style={styles.footer}>
|
||||
© 2026 Bali Interaktif Perkasa. All rights reserved.
|
||||
</Text>
|
||||
</ScrollView>
|
||||
|
||||
<TouchableOpacity
|
||||
onPress={handleAccept}
|
||||
disabled={!isAtBottom || isLoading}
|
||||
style={[styles.button, { opacity: !isAtBottom || isLoading ? 0.6 : 1 }]}
|
||||
>
|
||||
<Text style={styles.buttonText}>
|
||||
{isLoading ? "Menyimpan..." : "Saya Setuju"}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: MainColor.darkblue,
|
||||
padding: 16,
|
||||
},
|
||||
title: {
|
||||
fontSize: 20,
|
||||
fontWeight: "bold",
|
||||
textAlign: "center",
|
||||
marginBottom: 16,
|
||||
color: MainColor.white,
|
||||
},
|
||||
scrollView: {
|
||||
flex: 1,
|
||||
marginBottom: 20,
|
||||
},
|
||||
scrollContent: {
|
||||
paddingBottom: 30,
|
||||
},
|
||||
heading: {
|
||||
fontSize: 16,
|
||||
fontWeight: "600",
|
||||
marginTop: 16,
|
||||
marginBottom: 8,
|
||||
color: MainColor.white,
|
||||
},
|
||||
paragraph: {
|
||||
fontSize: 14,
|
||||
lineHeight: 22,
|
||||
color: MainColor.white,
|
||||
marginBottom: 12,
|
||||
},
|
||||
bold: {
|
||||
fontWeight: "600",
|
||||
},
|
||||
list: {
|
||||
marginLeft: 8,
|
||||
marginBottom: 12,
|
||||
},
|
||||
listItem: {
|
||||
fontSize: 14,
|
||||
lineHeight: 22,
|
||||
color: MainColor.white,
|
||||
marginBottom: 6,
|
||||
},
|
||||
footer: {
|
||||
fontSize: 12,
|
||||
color: MainColor.white,
|
||||
textAlign: "center",
|
||||
marginTop: 20,
|
||||
paddingTop: 10,
|
||||
borderTopWidth: 2,
|
||||
borderTopColor: AccentColor.blue,
|
||||
},
|
||||
button: {
|
||||
backgroundColor: MainColor.yellow,
|
||||
paddingVertical: 14,
|
||||
borderRadius: 8,
|
||||
alignItems: "center",
|
||||
width: 200,
|
||||
alignSelf: "center",
|
||||
},
|
||||
buttonText: {
|
||||
color: "#fff",
|
||||
fontSize: 16,
|
||||
fontWeight: "600",
|
||||
},
|
||||
});
|
||||
@@ -12,25 +12,6 @@ import { SafeAreaView } from "react-native-safe-area-context";
|
||||
import { AccentColor, MainColor } from "@/constants/color-palet";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
|
||||
// Ganti dengan API call ke backend Anda
|
||||
// const acceptEula = async (): Promise<boolean> => {
|
||||
// try {
|
||||
// const response = await fetch("/api/user/update-eula", {
|
||||
// method: "PATCH",
|
||||
// headers: { "Content-Type": "application/json" },
|
||||
// credentials: "include",
|
||||
// body: JSON.stringify({
|
||||
// eulaAcceptedAt: new Date().toISOString(),
|
||||
// eulaVersion: "2026-01-v1", // sesuaikan versi Anda
|
||||
// }),
|
||||
// });
|
||||
// return response.ok;
|
||||
// } catch (error) {
|
||||
// console.error("Gagal menyimpan persetujuan EULA:", error);
|
||||
// return false;
|
||||
// }
|
||||
// };
|
||||
|
||||
export default function EULAView() {
|
||||
const { acceptedTerms } = useAuth();
|
||||
const { nomor } = useLocalSearchParams();
|
||||
@@ -52,7 +33,7 @@ export default function EULAView() {
|
||||
if (!isAtBottom) return;
|
||||
|
||||
setIsLoading(true);
|
||||
await acceptedTerms(nomor as string);
|
||||
// await acceptedTerms(nomor as string);
|
||||
} catch (error) {
|
||||
console.log("Error accept terms", error);
|
||||
} finally {
|
||||
|
||||
@@ -1,25 +1,31 @@
|
||||
import { NewWrapper } from "@/components";
|
||||
import { NewWrapper, TextCustom } from "@/components";
|
||||
import ButtonCustom from "@/components/Button/ButtonCustom";
|
||||
import ModalReactNative from "@/components/Modal/ModalReactNative";
|
||||
import Spacing from "@/components/_ShareComponent/Spacing";
|
||||
import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import { apiVersion } from "@/service/api-config";
|
||||
import { apiVersion, BASE_URL } from "@/service/api-config";
|
||||
import { GStyles } from "@/styles/global-styles";
|
||||
import { openBrowser } from "@/utils/openBrower";
|
||||
import versionBadge from "@/utils/viersionBadge";
|
||||
import VersionBadge from "@/utils/viersionBadge";
|
||||
import { Redirect } from "expo-router";
|
||||
import { useEffect, useState } from "react";
|
||||
import { RefreshControl, Text, View } from "react-native";
|
||||
import { Modal, RefreshControl, Text, View } from "react-native";
|
||||
import PhoneInput, { ICountry } from "react-native-international-phone-number";
|
||||
import Toast from "react-native-toast-message";
|
||||
import EULASection from "./EULASection";
|
||||
|
||||
export default function LoginView() {
|
||||
const url = BASE_URL;
|
||||
const [version, setVersion] = useState<string>("");
|
||||
const [selectedCountry, setSelectedCountry] = useState<null | ICountry>(null);
|
||||
const [inputValue, setInputValue] = useState<string>("");
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [refreshing, setRefreshing] = useState<boolean>(false);
|
||||
const [modalVisible, setModalVisible] = useState(false);
|
||||
const [numberToEULA, setNumberToEULA] = useState<string>("");
|
||||
|
||||
const { loginWithNomor, token, isAdmin, isUserActive } = useAuth();
|
||||
|
||||
@@ -85,9 +91,16 @@ export default function LoginView() {
|
||||
|
||||
const realNumber = callingCode + fixNumber;
|
||||
|
||||
|
||||
try {
|
||||
setLoading(true);
|
||||
await loginWithNomor(realNumber);
|
||||
const loginRes = await loginWithNomor(realNumber);
|
||||
|
||||
if (!loginRes) {
|
||||
setModalVisible(true);
|
||||
}
|
||||
|
||||
setNumberToEULA(realNumber);
|
||||
} catch (error) {
|
||||
console.log("Error login", error);
|
||||
Toast.show({
|
||||
@@ -98,30 +111,6 @@ export default function LoginView() {
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
// try {
|
||||
// setLoading(true);
|
||||
// // const response = await apiLogin({ nomor: realNumber });
|
||||
// const response = await loginWithNomor(realNumber);
|
||||
// console.log("[RESPONSE]", response);
|
||||
|
||||
// Toast.show({
|
||||
// type: "success",
|
||||
// text1: "Sukses",
|
||||
// text2: "Kode OTP berhasil dikirim",
|
||||
// });
|
||||
|
||||
// // router.navigate(`/verification?nomor=${realNumber}`);
|
||||
// } catch (error) {
|
||||
// console.log("Error login", error);
|
||||
// Toast.show({
|
||||
// type: "error",
|
||||
// text1: "Error",
|
||||
// text2: error as string,
|
||||
// });
|
||||
// } finally {
|
||||
// setLoading(false);
|
||||
// }
|
||||
}
|
||||
|
||||
if (token && token !== "" && !isUserActive) {
|
||||
@@ -148,6 +137,7 @@ export default function LoginView() {
|
||||
}
|
||||
>
|
||||
<View style={GStyles.authContainer}>
|
||||
|
||||
<View>
|
||||
<View style={GStyles.authContainerTitle}>
|
||||
<Text style={GStyles.authSubTitle}>WELCOME TO</Text>
|
||||
@@ -185,11 +175,41 @@ export default function LoginView() {
|
||||
<ButtonCustom onPress={handleLogin} isLoading={loading}>
|
||||
Login
|
||||
</ButtonCustom>
|
||||
<Spacing />
|
||||
{/* <ButtonCustom onPress={() => router.navigate("/(application)/coba")}>
|
||||
Coba
|
||||
<Spacing height={50} />
|
||||
|
||||
{/* <ButtonCustom
|
||||
onPress={() => {
|
||||
setModalVisible(true);
|
||||
console.log("Show modal", modalVisible);
|
||||
}}
|
||||
>
|
||||
Show Modal
|
||||
</ButtonCustom> */}
|
||||
{/* <CheckboxCustom value={term} onChange={() => setTerm(!term)} /> */}
|
||||
|
||||
<Text
|
||||
style={{ ...GStyles.textLabel, textAlign: "center", fontSize: 12 }}
|
||||
>
|
||||
Dengan menggunakan aplikasi ini, Anda telah menyetujui{" "}
|
||||
<Text
|
||||
style={{
|
||||
color: MainColor.yellow,
|
||||
textDecorationLine: "underline",
|
||||
}}
|
||||
onPress={() => {
|
||||
const toUrl = `${url}/terms-of-service.html`;
|
||||
openBrowser(toUrl);
|
||||
}}
|
||||
>
|
||||
Syarat & Ketentuan
|
||||
</Text>{" "}
|
||||
dan seluruh kebijakan privasi yang berlaku.
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<ModalReactNative isVisible={modalVisible}>
|
||||
<EULASection nomor={numberToEULA || ""} onSetModalVisible={setModalVisible} />
|
||||
</ModalReactNative>
|
||||
</NewWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,8 @@ export const tabsHome: any = ({
|
||||
icon: "chatbubble-ellipses-outline",
|
||||
activeIcon: "chatbubble-ellipses",
|
||||
label: "Forum",
|
||||
path: acceptedForumTermsAt ? "/forum" : "/forum/terms",
|
||||
// path: acceptedForumTermsAt ? "/forum" : "/forum/terms",
|
||||
path: "/forum",
|
||||
isActive: true,
|
||||
disabled: false,
|
||||
},
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
TextCustom,
|
||||
} from "@/components";
|
||||
import API_STRORAGE from "@/constants/base-url-api-strorage";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import DUMMY_IMAGE from "@/constants/dummy-image-value";
|
||||
import { countDownAndCondition } from "@/utils/countDownAndCondition";
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
@@ -22,8 +21,6 @@ export default function Investment_BoxBerandaSection({
|
||||
id: string;
|
||||
data: any;
|
||||
}) {
|
||||
// console.log("[DATA By one]", JSON.stringify(data, null, 2));
|
||||
|
||||
const [value, setValue] = useState({
|
||||
sisa: 0,
|
||||
reminder: false,
|
||||
@@ -33,8 +30,6 @@ export default function Investment_BoxBerandaSection({
|
||||
updateCountDown();
|
||||
}, [data]);
|
||||
|
||||
console.log("[DATA BERANDA]", JSON.stringify(data, null, 2));
|
||||
|
||||
const updateCountDown = () => {
|
||||
const countDown = countDownAndCondition({
|
||||
duration: data?.pencarianInvestor,
|
||||
|
||||
@@ -1,13 +1,25 @@
|
||||
import { BaseBox, StackCustom, TextCustom, ProgressCustom } from "@/components";
|
||||
|
||||
export default function Invesment_BoxProgressSection({progress, status}: {progress: number, status: string}) {
|
||||
export default function Invesment_BoxProgressSection({
|
||||
progress,
|
||||
status,
|
||||
}: {
|
||||
progress: number;
|
||||
status: string;
|
||||
}) {
|
||||
return (
|
||||
<>
|
||||
{status === "publish" && (
|
||||
<BaseBox>
|
||||
<StackCustom>
|
||||
<TextCustom bold>Progress Saham</TextCustom>
|
||||
<ProgressCustom label={(progress || 0) + "%"} value={progress || 0} size="lg" />
|
||||
<ProgressCustom
|
||||
label={(progress || 0) + "%"}
|
||||
value={progress || 0}
|
||||
size="lg"
|
||||
animated
|
||||
color="primary"
|
||||
/>
|
||||
</StackCustom>
|
||||
</BaseBox>
|
||||
)}
|
||||
|
||||
@@ -70,7 +70,7 @@ export const drawerItemsProfile = ({
|
||||
color={AccentColor.white}
|
||||
/>
|
||||
),
|
||||
label: "Blocked List",
|
||||
label: "Daftar Blokir",
|
||||
path: `/(application)/profile/${id}/blocked-list`,
|
||||
value: "blocked-list",
|
||||
},
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { typeRejectedData } from "@/types/type-collect-other";
|
||||
import { apiConfig } from "../api-config";
|
||||
|
||||
export async function apiAdminDonation({
|
||||
@@ -33,7 +34,7 @@ export async function apiAdminDonationUpdateStatus({
|
||||
}: {
|
||||
id: string;
|
||||
changeStatus: "publish" | "review" | "reject";
|
||||
data?: string;
|
||||
data?: typeRejectedData;
|
||||
}) {
|
||||
try {
|
||||
const response = await apiConfig.put(
|
||||
|
||||
@@ -57,9 +57,19 @@ export async function apiAdminForumListReportCommentById({
|
||||
}
|
||||
}
|
||||
|
||||
export async function apiAdminForumDeactivateComment({ id }: { id: string }) {
|
||||
export async function apiAdminForumDeactivateComment({
|
||||
id,
|
||||
data,
|
||||
}: {
|
||||
id: string;
|
||||
data: { senderId: string };
|
||||
}) {
|
||||
|
||||
console.log("data", data)
|
||||
try {
|
||||
const response = await apiConfig.put(`/mobile/admin/forum/${id}/comment`);
|
||||
const response = await apiConfig.put(`/mobile/admin/forum/${id}/comment`, {
|
||||
data: data,
|
||||
});
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
@@ -81,9 +91,17 @@ export async function apiAdminForumListReportPostingById({
|
||||
}
|
||||
}
|
||||
|
||||
export async function apiAdminForumDeactivatePosting({ id }: { id: string }) {
|
||||
export async function apiAdminForumDeactivatePosting({
|
||||
id,
|
||||
data,
|
||||
}: {
|
||||
id: string;
|
||||
data: { senderId: string };
|
||||
}) {
|
||||
try {
|
||||
const response = await apiConfig.put(`/mobile/admin/forum/${id}`);
|
||||
const response = await apiConfig.put(`/mobile/admin/forum/${id}`, {
|
||||
data: data,
|
||||
});
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { typeRejectedData } from "@/types/type-collect-other";
|
||||
import { apiConfig } from "../api-config";
|
||||
|
||||
export async function apiAdminInvestment({
|
||||
@@ -38,7 +39,7 @@ export async function apiAdminInvestasiUpdateByStatus({
|
||||
}: {
|
||||
id: string;
|
||||
status: "publish" | "review" | "reject";
|
||||
data: any;
|
||||
data: typeRejectedData;
|
||||
}) {
|
||||
try {
|
||||
const response = await apiConfig.put(
|
||||
@@ -97,6 +98,7 @@ export async function apiAdminInvestmentUpdateInvoice({
|
||||
data: {
|
||||
investasiId: string;
|
||||
lembarTerbeli: number;
|
||||
senderId: string
|
||||
};
|
||||
}) {
|
||||
try {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { typeRejectedData } from "@/types/type-collect-other";
|
||||
import { apiConfig } from "../api-config";
|
||||
|
||||
export async function apiAdminVoting({
|
||||
@@ -32,7 +33,7 @@ export async function apiAdminVotingUpdateStatus({
|
||||
status,
|
||||
}: {
|
||||
id: string;
|
||||
data?: string;
|
||||
data?: typeRejectedData;
|
||||
status: "publish" | "review" | "reject";
|
||||
}) {
|
||||
try {
|
||||
|
||||
@@ -119,3 +119,62 @@ export async function apiForumDeleteComment({ id }: { id: string }) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function apiForumGetReportPosting({id}: {id:string}) {
|
||||
try {
|
||||
const response = await apiConfig.get(`/mobile/forum/${id}/preview-report-posting`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function apiForumGetReportComment({id}: {id:string}) {
|
||||
try {
|
||||
const response = await apiConfig.get(`/mobile/forum/${id}/preview-report-comment`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export async function apiForumCreateReportPosting({
|
||||
id,
|
||||
data,
|
||||
}: {
|
||||
id: string;
|
||||
data: any;
|
||||
}) {
|
||||
try {
|
||||
const response = await apiConfig.post(
|
||||
`/mobile/forum/${id}/report-posting`,
|
||||
{
|
||||
data: data,
|
||||
}
|
||||
);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function apiForumCreateReportCommentar({
|
||||
id,
|
||||
data,
|
||||
}: {
|
||||
id: string;
|
||||
data: any;
|
||||
}) {
|
||||
try {
|
||||
const response = await apiConfig.post(
|
||||
`/mobile/forum/${id}/report-commentar`,
|
||||
{
|
||||
data: data,
|
||||
}
|
||||
);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@@ -77,46 +77,6 @@ export async function apiMasterForumReportList() {
|
||||
|
||||
// ================== END MASTER FORUM ================== //
|
||||
|
||||
export async function apiForumCreateReportPosting({
|
||||
id,
|
||||
data,
|
||||
}: {
|
||||
id: string;
|
||||
data: any;
|
||||
}) {
|
||||
try {
|
||||
const response = await apiConfig.post(
|
||||
`/mobile/forum/${id}/report-posting`,
|
||||
{
|
||||
data: data,
|
||||
}
|
||||
);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function apiForumCreateReportCommentar({
|
||||
id,
|
||||
data,
|
||||
}: {
|
||||
id: string;
|
||||
data: any;
|
||||
}) {
|
||||
try {
|
||||
const response = await apiConfig.post(
|
||||
`/mobile/forum/${id}/report-commentar`,
|
||||
{
|
||||
data: data,
|
||||
}
|
||||
);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// ================== START MASTER INVESTMENT ================== //
|
||||
|
||||
export async function apiMasterInvestment({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export type RejectedData = {
|
||||
export type typeRejectedData = {
|
||||
catatan?: string;
|
||||
senderId: string;
|
||||
};
|
||||
|
||||
15
types/type-forum.ts
Normal file
15
types/type-forum.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
export interface TypeForum_CommentProps {
|
||||
id: string;
|
||||
isActive: boolean;
|
||||
komentar: string;
|
||||
createdAt: Date;
|
||||
authorId: string;
|
||||
Author: {
|
||||
id: string;
|
||||
username: string;
|
||||
Profile: {
|
||||
id: string;
|
||||
imageId: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -5,11 +5,11 @@ const badWordsIndonesia = [
|
||||
'anjing', 'babi', 'bangsat', 'bodoh', 'goblok', 'idiot', 'jancok', 'jembut', 'kampret',
|
||||
'kontol', 'memek', 'ngentot', 'peler', 'puki', 'sialan', 'tai', 'tolol', 'wibu',
|
||||
'anjingg', 'babbii', 'bangsaat', 'gobllokk', 'jancokk', 'kontoll', 'memekk', 'ngentott',
|
||||
'pelerr', 'puuki', 'sialann', 'taii', 'tololl', 'wibuu',
|
||||
'pelerr', 'puuki', 'sialann', 'taii', 'tololl', 'wibuu', 'cicing',
|
||||
|
||||
// 🔥 Kata Sindiran & Penghinaan
|
||||
'bego', 'dungu', 'edan', 'gila', 'goblog', 'kampang', 'kampret', 'keparat', 'lonte',
|
||||
'main mata', 'monyet', 'najis', 'ngeyel', 'ngibul', 'ngomong seenaknya', 'ngurangin',
|
||||
'monyet', 'najis', 'ngeyel', 'ngibul', 'ngomong seenaknya', 'ngurangin',
|
||||
'ngutang', 'ngurusin urusan orang', 'pemalas', 'pengecut', 'penipu', 'sinting',
|
||||
'begoo', 'dunguu', 'goblogg', 'kampangg', 'keparatt', 'lontee', 'monyyet', 'najiss',
|
||||
'ngeyell', 'ngibull', 'ngomongg seenaknya', 'nguranginn', 'ngutangg', 'pemalass',
|
||||
@@ -23,18 +23,17 @@ const badWordsIndonesia = [
|
||||
|
||||
// 💸 Kata Spam / Promosi Ilegal
|
||||
'judi', 'togel', 'slot', 'casino', 'poker', 'qq', 'bandar', 'agen', 'link', 'wa',
|
||||
'whatsapp', 'telepon', 'nomor', 'hp', 'sms', 'grup', 'join', 'daftar', 'bonus',
|
||||
'deposit', 'withdraw', 'uang', 'duit', 'rp', 'ratusan', 'juta', 'milyar',
|
||||
'deposit', 'withdraw',
|
||||
'judii', 'togell', 'slotss', 'casinoo', 'pokerr', 'qqq', 'bandarr', 'agenn', 'linkk',
|
||||
'waa', 'whatsappp', 'teleponn', 'nomorr', 'hpp', 'smss', 'grupp', 'jooin', 'daftarr',
|
||||
'bonuss', 'depositt', 'withdraww', 'uangs', 'duitt', 'rpp', 'ratusann', 'jutaa', 'milyarr',
|
||||
'waa',
|
||||
'depositt', 'withdraww', 'rpp',
|
||||
|
||||
// 🧩 Variasi Penulisan (Bypass Filter)
|
||||
'a*njing', 'b*b*i', 'b*ngsat', 'g*blok', 'k*nt*l', 'm*m*k', 'n*g*nt*t', 'p*l*r',
|
||||
't*i', 't*l*l', 'j*n*c*k', 'j*m*b*t', 'k*m*p*r*t', 's*i*l*a*n', 'w*b*u',
|
||||
'a.n.j.i.n.g', 'b.a.b.i', 'b.a.n.g.s.a.t', 'g.o.b.l.o.k', 'k.o.n.t.o.l', 'm.e.m.e.k',
|
||||
'n.g.e.n.t.o.t', 'p.e.l.e.r', 't.a.i', 't.o.l.o.l', 'j.a.n.c.o.k', 'j.e.m.b.u.t',
|
||||
'k.a.m.p.r.e.t', 's.i.a.l.a.n', 'w.i.b.u',
|
||||
'k.a.m.p.r.e.t', 's.i.a.l.a.n', 'w.i.b.u', 'c.i.c.i.n.g',
|
||||
|
||||
// 📱 Variasi dengan Angka & Simbol
|
||||
'4nj1ng', 'b4b1', 'b4ngs4t', 'g0bl0k', 'k0nt0l', 'm3m3k', 'ng3nt0t', 'p3l3r',
|
||||
@@ -43,8 +42,6 @@ const badWordsIndonesia = [
|
||||
'p3l3rr', 't4ii', 't0l0ll', 'j4nc0kk', 'j3mbutt', 'k4mpr3tt', 's14l4nn', 'w1buu',
|
||||
|
||||
// 🗣️ Kata yang Sering Digunakan dalam Konteks Negatif
|
||||
'dasar', 'kamu', 'kau', 'lu', 'lo', 'gue', 'gua', 'kita', 'kami', 'mereka',
|
||||
'dasarr', 'kamuu', 'kauu', 'luu', 'loo', 'guee', 'guua', 'kitaa', 'kamii', 'merekaa',
|
||||
'dasar bodoh', 'dasar goblok', 'dasar bangsat', 'dasar idiot', 'dasar sialan',
|
||||
'dasar bego', 'dasar dungu', 'dasar edan', 'dasar gila', 'dasar sinting',
|
||||
'dasar pemalas', 'dasar pengecut', 'dasar penipu', 'dasar najis', 'dasar kampret',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as ImagePicker from "expo-image-picker";
|
||||
import * as DocumentPicker from "expo-document-picker";
|
||||
import { Alert } from "react-native";
|
||||
import { Alert, Platform } from "react-native";
|
||||
|
||||
const ALLOWED_IMAGE_EXTENSIONS = ["jpg", "jpeg", "png"];
|
||||
const MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB
|
||||
@@ -33,22 +33,52 @@ export default async function pickFile({
|
||||
await pickImage(setImageUri, aspectRatio);
|
||||
} else {
|
||||
// Jika tidak, tawarkan pilihan rasio (default [4,3])
|
||||
// 🚀 Hanya tampilkan pilihan rasio di ANDROID
|
||||
if (Platform.OS === "android") {
|
||||
showAspectRatioChoice(setImageUri);
|
||||
} else {
|
||||
// iOS: langsung buka galeri dengan default [4, 3]
|
||||
await pickImage(setImageUri, [4, 3]);
|
||||
}
|
||||
}
|
||||
} else if (allowedType === "pdf") {
|
||||
await pickPdf(setPdfUri);
|
||||
} else {
|
||||
// Mode fleksibel: tampilkan pilihan
|
||||
// Alert.alert(
|
||||
// "Pilih Jenis File",
|
||||
// "Pilih sumber file yang ingin diunggah:",
|
||||
// [
|
||||
// { text: "Batal", style: "cancel" },
|
||||
// { text: "Dokumen (PDF)", onPress: () => pickPdf(setPdfUri) },
|
||||
// { text: "Gambar", onPress: () => pickImage(setImageUri, aspectRatio) },
|
||||
// ],
|
||||
// { cancelable: true }
|
||||
// );
|
||||
if (Platform.OS === "android") {
|
||||
Alert.alert(
|
||||
"Pilih Jenis File",
|
||||
"Pilih sumber file yang ingin diunggah:",
|
||||
[
|
||||
{ text: "Batal", style: "cancel" },
|
||||
{ text: "Dokumen (PDF)", onPress: () => pickPdf(setPdfUri) },
|
||||
{ text: "Gambar", onPress: () => pickImage(setImageUri, aspectRatio) },
|
||||
{ text: "Gambar", onPress: () => showAspectRatioChoice(setImageUri) },
|
||||
],
|
||||
{ cancelable: true }
|
||||
);
|
||||
} else {
|
||||
// iOS: Langsung pakai default [4,3] untuk gambar
|
||||
Alert.alert(
|
||||
"Pilih Jenis File",
|
||||
"Pilih sumber file yang ingin diunggah:",
|
||||
[
|
||||
{ text: "Batal", style: "cancel" },
|
||||
{ text: "Dokumen (PDF)", onPress: () => pickPdf(setPdfUri) },
|
||||
{ text: "Gambar", onPress: () => pickImage(setImageUri, [4, 3]) },
|
||||
],
|
||||
{ cancelable: true }
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user