Merge pull request 'Fix QC Admin' (#25) from qc/5-dec-25 into main

Reviewed-on: http://wibugit.wibudev.com/wibu/hipmi-mobile/pulls/25
This commit is contained in:
2025-12-05 17:23:16 +08:00
25 changed files with 398 additions and 155 deletions

View File

@@ -100,7 +100,7 @@ packagingOptions {
applicationId 'com.bip.hipmimobileapp'
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 2
versionCode 3
versionName "1.0.1"
buildConfigField "String", "REACT_NATIVE_RELEASE_LEVEL", "\"${findProperty('reactNativeReleaseLevel') ?: 'stable'}\""

View File

@@ -19,7 +19,7 @@ export default {
"NSLocationWhenInUseUsageDescription": "Aplikasi membutuhkan akses lokasi untuk menampilkan peta.",
},
associatedDomains: ["applinks:cld-dkr-staging-hipmi.wibudev.com"],
buildNumber: "12",
buildNumber: "13",
},
android: {
@@ -30,7 +30,7 @@ export default {
},
edgeToEdgeEnabled: true,
package: "com.bip.hipmimobileapp",
versionCode: 2,
versionCode: 3,
// softwareKeyboardLayoutMode: 'resize', // option: untuk mengatur keyboard pada room chst collaboration
intentFilters: [
{

View File

@@ -5,9 +5,12 @@ import {
TextAreaCustom,
ViewWrapper,
} from "@/components";
import AlertWarning from "@/components/Alert/AlertWarning";
import { apiForumGetOne, apiForumUpdate } from "@/service/api-client/api-forum";
import { isBadContent } from "@/utils/badWordsIndonesia";
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
import { useCallback, useState } from "react";
import { Alert } from "react-native";
import Toast from "react-native-toast-message";
export default function ForumEdit() {
@@ -43,6 +46,12 @@ export default function ForumEdit() {
});
return;
}
if (isBadContent(text)) {
AlertWarning({});
return;
}
try {
setIsLoading(true);
const response = await apiForumUpdate({

View File

@@ -7,6 +7,7 @@ import {
TextCustom,
ViewWrapper,
} from "@/components";
import AlertWarning from "@/components/Alert/AlertWarning";
import { useAuth } from "@/hooks/use-auth";
import Forum_CommentarBoxSection from "@/screens/Forum/CommentarBoxSection";
import Forum_BoxDetailSection from "@/screens/Forum/DiscussionBoxSection";
@@ -18,9 +19,11 @@ import {
apiForumGetOne,
apiForumUpdateStatus,
} from "@/service/api-client/api-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;
@@ -110,11 +113,15 @@ export default function ForumDetail() {
// Create Commentar
const handlerCreateCommentar = async () => {
if (isBadContent(text)) {
AlertWarning({});
return;
}
const newData = {
comment: text,
authorId: user?.id,
};
try {
setLoadingComment(true);
const response = await apiForumCreateComment({

View File

@@ -2,12 +2,15 @@ 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 { router } from "expo-router";
import { useState } from "react";
import { Alert } from "react-native";
import Toast from "react-native-toast-message";
export default function ForumCreate() {
@@ -16,11 +19,16 @@ export default function ForumCreate() {
const [isLoading, setIsLoading] = useState(false);
const handlerSubmit = async () => {
if (isBadContent(text)) {
AlertWarning({})
return;
}
const newData = {
diskusi: text,
authorId: user?.id,
};
try {
setIsLoading(true);
const response = await apiForumCreate({ data: newData });

View File

@@ -18,7 +18,7 @@ import { IconDot, IconList } from "@/components/_Icon/IconComponent";
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
import AdminButtonReject from "@/components/_ShareComponent/Admin/ButtonReject";
import AdminButtonReview from "@/components/_ShareComponent/Admin/ButtonReview";
import { GridDetail_4_8 } from "@/components/_ShareComponent/GridDetail_4_8";
import { GridSpan_4_8 } from "@/components/_ShareComponent/GridSpan_4_8";
import ReportBox from "@/components/Box/ReportBox";
import { ICON_SIZE_BUTTON, TEXT_SIZE_LARGE } from "@/constants/constans-value";
import AdminDonation_BoxOfDonationStory from "@/screens/Admin/Donation/BoxOfDonationStory";
@@ -195,7 +195,7 @@ export default function AdminDonationDetail() {
<StackCustom gap={5}>
{listPencarianDana.map((item, i) => (
<GridDetail_4_8
<GridSpan_4_8
key={i}
label={<TextCustom bold>{item.label}</TextCustom>}
value={<TextCustom>{item.value}</TextCustom>}
@@ -236,7 +236,7 @@ export default function AdminDonationDetail() {
<Spacing />
<StackCustom gap={"xs"}>
<GridDetail_4_8
<GridSpan_4_8
label={<TextCustom bold>Jumlah Donatur</TextCustom>}
value={
<TextCustom>
@@ -244,7 +244,7 @@ export default function AdminDonationDetail() {
</TextCustom>
}
/>
<GridDetail_4_8
<GridSpan_4_8
label={<TextCustom bold>Dana Terkumpul</TextCustom>}
value={
<TextCustom>
@@ -261,7 +261,7 @@ export default function AdminDonationDetail() {
<StackCustom>
<DummyLandscapeImage imageId={data?.imageId || ""} />
{listData.map((item, i) => (
<GridDetail_4_8
<GridSpan_4_8
key={i}
label={<TextCustom bold>{item.label}</TextCustom>}
value={<TextCustom>{item.value}</TextCustom>}

View File

@@ -8,7 +8,7 @@ import {
ViewWrapper,
} from "@/components";
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
import { GridDetail_4_8 } from "@/components/_ShareComponent/GridDetail_4_8";
import { GridSpan_4_8 } from "@/components/_ShareComponent/GridSpan_4_8";
import {
apiAdminDonationInvoiceDetailById,
apiAdminDonationInvoiceUpdateById,
@@ -177,7 +177,7 @@ export default function AdminDonasiTransactionDetail() {
<BaseBox>
<StackCustom>
{listData.map((item, index) => (
<GridDetail_4_8
<GridSpan_4_8
key={index}
label={<TextCustom bold>{item.label}</TextCustom>}
value={<TextCustom>{item.value}</TextCustom>}

View File

@@ -7,7 +7,7 @@ import {
ViewWrapper,
} from "@/components";
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
import { GridDetail_4_8 } from "@/components/_ShareComponent/GridDetail_4_8";
import { GridSpan_4_8 } from "@/components/_ShareComponent/GridSpan_4_8";
import { apiAdminDonationDisbursementOfFundsListById } from "@/service/api-admin/api-admin-donation";
import { dateTimeView } from "@/utils/dateTimeView";
import { formatCurrencyDisplay } from "@/utils/formatCurrencyDisplay";
@@ -67,7 +67,7 @@ export default function AdminDonationDetailDisbursementOfFunds() {
<BaseBox>
<StackCustom>
{listData?.map((item, index) => (
<GridDetail_4_8
<GridSpan_4_8
key={index}
label={<TextCustom bold>{item.label}</TextCustom>}
value={<TextCustom>{item.value}</TextCustom>}

View File

@@ -1,30 +1,22 @@
import {
ActionIcon,
BadgeCustom,
BaseBox,
CenterCustom,
ClickableCustom,
DividerCustom,
Grid,
Spacing,
StackCustom,
TextCustom,
ViewWrapper,
ViewWrapper
} from "@/components";
import { IconEdit } from "@/components/_Icon";
import AdminActionIconPlus from "@/components/_ShareComponent/Admin/ActionIconPlus";
import AdminComp_BoxTitle from "@/components/_ShareComponent/Admin/BoxTitlePage";
import AdminTitlePage from "@/components/_ShareComponent/Admin/TitlePage";
import { GridView_3_3_6 } from "@/components/_ShareComponent/GridView_3_3_6";
import { MainColor } from "@/constants/color-palet";
import { ICON_SIZE_BUTTON } from "@/constants/constans-value";
import { RefreshControl, View } from "react-native";
import { Divider, Switch } from "react-native-paper";
import { router, useFocusEffect } from "expo-router";
import { useCallback, useEffect, useState } from "react";
import { GridSpan_4_8 } from "@/components/_ShareComponent/GridSpan_4_8";
import { apiAdminMasterDonationCategory } from "@/service/api-admin/api-master-admin";
import { GridDetail_4_8 } from "@/components/_ShareComponent/GridDetail_4_8";
import GridTwoView from "@/components/_ShareComponent/GridTwoView";
import { colorActivationForBadge } from "@/utils/colorActivationForBadge";
import { router, useFocusEffect } from "expo-router";
import { useCallback, useState } from "react";
import { RefreshControl, View } from "react-native";
import { Divider } from "react-native-paper";
export default function AdminDonationCategory() {
const [listData, setListData] = useState<any[]>([]);
@@ -80,14 +72,18 @@ export default function AdminDonationCategory() {
/>
<View>
<Grid>
<GridSpan_4_8
label={<TextCustom bold>Status</TextCustom>}
value={<TextCustom bold>Kategori</TextCustom>}
/>
{/* <Grid>
<Grid.Col style={{ paddingLeft: 10 }} span={4}>
<TextCustom bold>Status</TextCustom>
</Grid.Col>
<Grid.Col span={8}>
<TextCustom bold>Kategori</TextCustom>
</Grid.Col>
</Grid>
</Grid> */}
<Divider />
<Spacing />
@@ -100,11 +96,22 @@ export default function AdminDonationCategory() {
}}
key={index}
>
<Grid containerStyle={{ paddingBottom: 10 }}>
<Grid.Col
span={4}
style={{paddingLeft: 10}}
<GridSpan_4_8
label={
<CenterCustom>
<BadgeCustom
color={colorActivationForBadge({
status: item.active,
})}
>
{item.active ? "Aktif" : "Tidak Aktif"}
</BadgeCustom>
</CenterCustom>
}
value={<TextCustom>{item.name}</TextCustom>}
/>
{/* <Grid containerStyle={{ paddingBottom: 10 }}>
<Grid.Col span={4} style={{ paddingLeft: 10 }}>
<CenterCustom>
<BadgeCustom
color={item.active ? MainColor.green : MainColor.red}
@@ -116,7 +123,7 @@ export default function AdminDonationCategory() {
<Grid.Col span={8}>
<TextCustom bold>{item.name}</TextCustom>
</Grid.Col>
</Grid>
</Grid> */}
<Divider />
</ClickableCustom>
))}

View File

@@ -16,7 +16,7 @@ import { IconDot, IconList } from "@/components/_Icon/IconComponent";
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
import AdminButtonReject from "@/components/_ShareComponent/Admin/ButtonReject";
import AdminButtonReview from "@/components/_ShareComponent/Admin/ButtonReview";
import { GridDetail_4_8 } from "@/components/_ShareComponent/GridDetail_4_8";
import { GridSpan_4_8 } from "@/components/_ShareComponent/GridSpan_4_8";
import ReportBox from "@/components/Box/ReportBox";
import { ICON_SIZE_BUTTON } from "@/constants/constans-value";
import { useAuth } from "@/hooks/use-auth";
@@ -39,6 +39,11 @@ export default function AdminEventDetail() {
const [data, setData] = React.useState<any | null>(null);
const [loadData, setLoadData] = React.useState(false);
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;
useFocusEffect(
useCallback(() => {
onLoadData();
@@ -156,7 +161,7 @@ export default function AdminEventDetail() {
<BaseBox>
<StackCustom>
{listData.map((item, i) => (
<GridDetail_4_8
<GridSpan_4_8
key={i}
label={<TextCustom bold>{item.label}</TextCustom>}
value={<TextCustom>{item.value}</TextCustom>}
@@ -181,7 +186,7 @@ export default function AdminEventDetail() {
<LoaderCustom />
) : (
<QRCode
value={deepLinkURL}
value={isDevLink}
size={200}
// logo={require("@/assets/images/logo-hipmi.png")}
// logoSize={70}
@@ -191,7 +196,7 @@ export default function AdminEventDetail() {
/>
)}
<TextCustom align="center">{deepLinkURL}</TextCustom>
<TextCustom align="center">{isDevLink}</TextCustom>
</StackCustom>
</BaseBox>
)}

View File

@@ -10,14 +10,17 @@ import {
} from "@/components";
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
import { apiAdminEventListOfParticipants } from "@/service/api-admin/api-admin-event";
import dayjs, { Dayjs } from "dayjs";
import { useFocusEffect, useLocalSearchParams } from "expo-router";
import _ from "lodash";
import { View } from "moti";
import { useCallback, useState } from "react";
export default function AdminEventListOfParticipants() {
const { id } = useLocalSearchParams();
const [listData, setListData] = useState<any[] | null>(null);
const [loadData, setLoadData] = useState(false);
const [startDate, setStartDate] = useState<Dayjs | undefined>();
useFocusEffect(
useCallback(() => {
@@ -32,8 +35,11 @@ export default function AdminEventListOfParticipants() {
id: id as string,
});
console.log("[DATA]", JSON.stringify(response, null, 2));
if (response.success) {
setListData(response.data);
setStartDate(dayjs(response.data.Event.tanggal));
}
} catch (error) {
console.log("[ERROR]", error);
@@ -42,7 +48,6 @@ export default function AdminEventListOfParticipants() {
}
};
return (
<>
<ViewWrapper
@@ -60,17 +65,35 @@ export default function AdminEventListOfParticipants() {
<Grid>
<Grid.Col span={6}>
<StackCustom gap={"sm"}>
<TextCustom bold truncate>{item?.User?.username}</TextCustom>
<TextCustom bold truncate>
{item?.User?.username}
</TextCustom>
<TextCustom>+{item?.User?.nomor}</TextCustom>
</StackCustom>
</Grid.Col>
<Grid.Col span={6} style={{ justifyContent: "center" }}>
{startDate &&
startDate.subtract(1, "hour").diff(dayjs()) < 0 ? (
<BadgeCustom
style={{ alignSelf: "flex-end" }}
color={item?.isPresent ? "green" : "red"}
>
{item?.isPresent ? "Hadir" : "Tidak Hadir"}
</BadgeCustom>
) : (
<View
style={{
justifyContent: "flex-end",
}}
>
<BadgeCustom
style={{ alignSelf: "flex-end" }}
color="gray"
>
-
</BadgeCustom>
</View>
)}
</Grid.Col>
</Grid>
</BaseBox>

View File

@@ -1,11 +1,12 @@
/* eslint-disable react-hooks/exhaustive-deps */
import {
ActionIcon,
ClickableCustom,
LoaderCustom,
SearchInput,
StackCustom,
TextCustom,
ViewWrapper
ViewWrapper,
} from "@/components";
import AdminComp_BoxTitle from "@/components/_ShareComponent/Admin/BoxTitlePage";
import AdminTitleTable from "@/components/_ShareComponent/Admin/TableTitle";
@@ -13,6 +14,7 @@ import AdminTableValue from "@/components/_ShareComponent/Admin/TableValue";
import AdminTitlePage from "@/components/_ShareComponent/Admin/TitlePage";
import { ICON_SIZE_BUTTON } from "@/constants/constans-value";
import { apiAdminEvent } from "@/service/api-admin/api-admin-event";
import { dateTimeView } from "@/utils/dateTimeView";
import { Octicons } from "@expo/vector-icons";
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
import _ from "lodash";
@@ -74,8 +76,8 @@ export default function AdminEventStatus() {
<StackCustom gap={"sm"}>
<AdminTitleTable
title1="Aksi"
title2="Username"
title1="Username"
title2="Tanggal"
title3="Judul Event"
/>
<Divider />
@@ -83,36 +85,47 @@ export default function AdminEventStatus() {
{loadData ? (
<LoaderCustom />
) : _.isEmpty(listData) ? (
<TextCustom align="center" size="small" color="gray">Belum ada data</TextCustom>
<TextCustom align="center" size="small" color="gray">
Belum ada data
</TextCustom>
) : (
listData?.map((item, index) => (
<AdminTableValue
<ClickableCustom
key={index}
value1={
<ActionIcon
icon={
<Octicons
name="eye"
size={ICON_SIZE_BUTTON}
color="black"
/>
}
onPress={() => {
router.push(`/admin/event/${item.id}/${status}`);
}}
/>
}
value2={
>
<AdminTableValue
key={index}
value1={
<TextCustom truncate={1}>
{item?.Author?.username || "-"}
</TextCustom>
// <ActionIcon
// icon={
// <Octicons
// name="eye"
// size={ICON_SIZE_BUTTON}
// color="black"
// />
// }
// onPress={() => {
// router.push(`/admin/event/${item.id}/${status}`);
// }}
// />
}
value3={
<TextCustom align="center" truncate={2}>
{item?.title || "-"}
value2={
<TextCustom truncate={1}>
{dateTimeView({ date: item?.tanggal })}
</TextCustom>
}
value3={
<TextCustom truncate={2}>{item?.title || "-"}</TextCustom>
}
/>
<Divider/>
</ClickableCustom>
))
)}
</StackCustom>

View File

@@ -11,7 +11,7 @@ import {
} from "@/components";
import { IconDot } from "@/components/_Icon/IconComponent";
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
import { GridDetail_4_8 } from "@/components/_ShareComponent/GridDetail_4_8";
import { GridSpan_4_8 } from "@/components/_ShareComponent/GridSpan_4_8";
import { MainColor } from "@/constants/color-palet";
import { ICON_SIZE_XLARGE } from "@/constants/constans-value";
import { apiAdminForumPostingById } from "@/service/api-admin/api-admin-forum";
@@ -103,7 +103,7 @@ export default function AdminForumDetailPosting() {
<BaseBox>
<StackCustom gap={"sm"}>
{listDataAction.map((item, i) => (
<GridDetail_4_8
<GridSpan_4_8
key={i}
label={<TextCustom bold>{item.label}</TextCustom>}
value={<TextCustom>{item.value}</TextCustom>}

View File

@@ -16,7 +16,7 @@ import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButt
import AdminComp_BoxTitle from "@/components/_ShareComponent/Admin/BoxTitlePage";
import AdminTitleTable from "@/components/_ShareComponent/Admin/TableTitle";
import AdminTableValue from "@/components/_ShareComponent/Admin/TableValue";
import { GridDetail_4_8 } from "@/components/_ShareComponent/GridDetail_4_8";
import { GridSpan_4_8 } from "@/components/_ShareComponent/GridSpan_4_8";
import { MainColor } from "@/constants/color-palet";
import { ICON_SIZE_BUTTON } from "@/constants/constans-value";
import {
@@ -95,11 +95,11 @@ export default function AdminForumReportComment() {
>
<BaseBox>
<StackCustom gap={"sm"}>
<GridDetail_4_8
<GridSpan_4_8
label={<TextCustom bold>Username</TextCustom>}
value={<TextCustom>{data?.Author?.username || "-"}</TextCustom>}
/>
<GridDetail_4_8
<GridSpan_4_8
label={<TextCustom bold>Komentar</TextCustom>}
value={<TextCustom>{data?.komentar || "-"}</TextCustom>}
/>
@@ -208,20 +208,20 @@ export default function AdminForumReportComment() {
height={"auto"}
>
<StackCustom>
<GridDetail_4_8
<GridSpan_4_8
label={<TextCustom bold>Pelapor</TextCustom>}
value={<TextCustom>{selectedReport?.username || "-"}</TextCustom>}
/>
{selectedReport?.kategori && (
<>
<GridDetail_4_8
<GridSpan_4_8
label={<TextCustom bold>Kategori Report</TextCustom>}
value={
<TextCustom>{selectedReport?.kategori || "-"}</TextCustom>
}
/>
<GridDetail_4_8
<GridSpan_4_8
label={<TextCustom bold>Keterangan</TextCustom>}
value={
<TextCustom>{selectedReport?.keterangan || "-"}</TextCustom>
@@ -231,7 +231,7 @@ export default function AdminForumReportComment() {
)}
{selectedReport?.deskripsi && (
<GridDetail_4_8
<GridSpan_4_8
label={<TextCustom bold>Deskripsi</TextCustom>}
value={
<TextCustom>{selectedReport?.deskripsi || "-"}</TextCustom>

View File

@@ -17,7 +17,7 @@ import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButt
import AdminComp_BoxTitle from "@/components/_ShareComponent/Admin/BoxTitlePage";
import AdminTitleTable from "@/components/_ShareComponent/Admin/TableTitle";
import AdminTableValue from "@/components/_ShareComponent/Admin/TableValue";
import { GridDetail_4_8 } from "@/components/_ShareComponent/GridDetail_4_8";
import { GridSpan_4_8 } from "@/components/_ShareComponent/GridSpan_4_8";
import { MainColor } from "@/constants/color-palet";
import { ICON_SIZE_BUTTON } from "@/constants/constans-value";
import {
@@ -95,12 +95,12 @@ export default function AdminForumReportPosting() {
>
<BaseBox>
<StackCustom gap={"sm"}>
<GridDetail_4_8
<GridSpan_4_8
label={<TextCustom bold>Username</TextCustom>}
value={<TextCustom>{data?.Author?.username || "-"}</TextCustom>}
/>
<GridDetail_4_8
<GridSpan_4_8
label={<TextCustom bold>Status</TextCustom>}
value={
data && data?.ForumMaster_StatusPosting?.status ? (
@@ -121,7 +121,7 @@ export default function AdminForumReportPosting() {
}
/>
<GridDetail_4_8
<GridSpan_4_8
label={<TextCustom bold>Postingan</TextCustom>}
value={<TextCustom>{data?.diskusi || "-"}</TextCustom>}
/>
@@ -229,20 +229,20 @@ export default function AdminForumReportPosting() {
height={"auto"}
>
<StackCustom>
<GridDetail_4_8
<GridSpan_4_8
label={<TextCustom bold>Pelapor</TextCustom>}
value={<TextCustom>{selectedReport?.username || "-"}</TextCustom>}
/>
{selectedReport?.kategori && (
<>
<GridDetail_4_8
<GridSpan_4_8
label={<TextCustom bold>Kategori Report</TextCustom>}
value={
<TextCustom>{selectedReport?.kategori || "-"}</TextCustom>
}
/>
<GridDetail_4_8
<GridSpan_4_8
label={<TextCustom bold>Keterangan</TextCustom>}
value={
<TextCustom>{selectedReport?.keterangan || "-"}</TextCustom>
@@ -252,7 +252,7 @@ export default function AdminForumReportPosting() {
)}
{selectedReport?.deskripsi && (
<GridDetail_4_8
<GridSpan_4_8
label={<TextCustom bold>Deskripsi</TextCustom>}
value={
<TextCustom>{selectedReport?.deskripsi || "-"}</TextCustom>

View File

@@ -19,7 +19,7 @@ import { IconDot, IconList } from "@/components/_Icon/IconComponent";
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
import AdminButtonReject from "@/components/_ShareComponent/Admin/ButtonReject";
import AdminButtonReview from "@/components/_ShareComponent/Admin/ButtonReview";
import { GridDetail_4_8 } from "@/components/_ShareComponent/GridDetail_4_8";
import { GridSpan_4_8 } from "@/components/_ShareComponent/GridSpan_4_8";
import ReportBox from "@/components/Box/ReportBox";
import { MainColor } from "@/constants/color-palet";
import { ICON_SIZE_BUTTON } from "@/constants/constans-value";
@@ -183,7 +183,7 @@ export default function AdminInvestmentDetail() {
/>
<Spacing />
<StackCustom gap={"xs"}>
<GridDetail_4_8
<GridSpan_4_8
label={<TextCustom bold>Sisa Saham</TextCustom>}
value={
<TextCustom>
@@ -191,7 +191,7 @@ export default function AdminInvestmentDetail() {
</TextCustom>
}
/>
<GridDetail_4_8
<GridSpan_4_8
label={<TextCustom bold>Validasi Transaksi</TextCustom>}
value={
<TextCustom>
@@ -207,7 +207,7 @@ export default function AdminInvestmentDetail() {
<StackCustom>
<DummyLandscapeImage imageId={data?.imageId} />
{listData.map((item, i) => (
<GridDetail_4_8
<GridSpan_4_8
key={i}
label={<TextCustom bold>{item.label}</TextCustom>}
value={<TextCustom>{item.value}</TextCustom>}
@@ -218,7 +218,7 @@ export default function AdminInvestmentDetail() {
<BaseBox>
<StackCustom>
<GridDetail_4_8
<GridSpan_4_8
label={<TextCustom bold>File Prospektus</TextCustom>}
value={
<ButtonCustom
@@ -238,7 +238,7 @@ export default function AdminInvestmentDetail() {
</ButtonCustom>
}
/>
<GridDetail_4_8
<GridSpan_4_8
label={<TextCustom bold>File Dokumen</TextCustom>}
value={
<StackCustom>

View File

@@ -10,7 +10,7 @@ import {
ViewWrapper,
} from "@/components";
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
import { GridDetail_4_8 } from "@/components/_ShareComponent/GridDetail_4_8";
import { GridSpan_4_8 } from "@/components/_ShareComponent/GridSpan_4_8";
import GridTwoView from "@/components/_ShareComponent/GridTwoView";
import { MainColor } from "@/constants/color-palet";
import {
@@ -225,7 +225,7 @@ export default function AdminInvestmentTransactionDetail() {
<BaseBox>
<StackCustom>
{listData.map((item, index) => (
<GridDetail_4_8
<GridSpan_4_8
key={index}
label={<TextCustom bold>{item.label}</TextCustom>}
value={<TextCustom>{item.value}</TextCustom>}

View File

@@ -13,7 +13,7 @@ import {
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
import AdminButtonReject from "@/components/_ShareComponent/Admin/ButtonReject";
import AdminButtonReview from "@/components/_ShareComponent/Admin/ButtonReview";
import { GridDetail_4_8 } from "@/components/_ShareComponent/GridDetail_4_8";
import { GridSpan_4_8 } from "@/components/_ShareComponent/GridSpan_4_8";
import ReportBox from "@/components/Box/ReportBox";
import { MainColor } from "@/constants/color-palet";
import funUpdateStatusVoting from "@/screens/Admin/Voting/funUpdateStatus";
@@ -169,7 +169,7 @@ export default function AdminVotingDetail() {
<BaseBox>
<StackCustom>
{listData.map((item, i) => (
<GridDetail_4_8
<GridSpan_4_8
key={i}
label={<TextCustom bold>{item.label}</TextCustom>}
value={<TextCustom>{item.value}</TextCustom>}

View File

@@ -0,0 +1,16 @@
import { Alert } from "react-native";
export default function AlertWarning({
title = "Peringatan Bagi Pengguna !",
description = "Konten yang Anda masukkan mengandung kata-kata yang tidak sesuai dengan pedoman komunitas kami. Mohon gunakan bahasa yang sopan dan menghargai sesama pengguna. Jika kata tersebut sebenarnya lumrah, mohon maaf—kemungkinan sistem kami belum mengenalnya sebagai wajar.",
}: {
title?: string
description?: string;
}) {
return Alert.alert(title, description, [
{
text: "Tutup",
onPress: () => {},
},
]);
}

View File

@@ -7,7 +7,7 @@ import DateTimePicker, {
} from "@react-native-community/datetimepicker";
import dayjs from "dayjs";
import React, { useState } from "react";
import { StyleProp, Text, View, ViewStyle } from "react-native";
import { Button, StyleProp, Text, View, ViewStyle } from "react-native";
import ClickableCustom from "../Clickable/ClickableCustom";
import TextCustom from "../Text/TextCustom";
@@ -129,24 +129,64 @@ const DateTimeInput_IOS: React.FC<DateTimeInputProps> = ({
borderWidth: 1,
}}
>
<View style={{ alignItems: "flex-end" }}>
{/* <View style={{ alignItems: "flex-start" }}>
<Ionicons
name="close"
size={20}
color="black"
onPress={() => setShow(false)}
onPress={() => {
setShow(false);
setSelectedDate(undefined);
}}
/>
</View>
</View> */}
<DateTimePicker
value={selectedDate || new Date()}
mode={"datetime"}
display="inline"
display="spinner"
onChange={handleConfirm}
minimumDate={minimumDate}
maximumDate={maximumDate}
themeVariant="light"
/>
<View style={{ flexDirection: "row", gap: 10 }}>
<ClickableCustom
onPress={() => {
setShow(false)
setSelectedDate(undefined)
}}
style={{
alignItems: "center",
justifyContent: "center",
padding: 12,
borderRadius: 10,
backgroundColor: MainColor.placeholder,
marginTop: 10,
width: "48%",
}}
>
<TextCustom color="black">Batal</TextCustom>
</ClickableCustom>
<ClickableCustom
onPress={() => {
setShow(false)
onChange(selectedDate as any)
}}
style={{
alignItems: "center",
justifyContent: "center",
padding: 12,
borderRadius: 10,
backgroundColor: MainColor.darkblue,
marginTop: 10,
width: "48%",
}}
>
<TextCustom>OK</TextCustom>
</ClickableCustom>
</View>
</View>
</>
)}

View File

@@ -15,7 +15,7 @@ export default function AdminButtonReject({
<>
<ButtonCustom
iconLeft={<IconReject size={16} />}
backgroundColor={MainColor.red}
backgroundColor={MainColor.orange}
textColor="white"
onPress={onReject}
isLoading={isLoading}

View File

@@ -1,20 +0,0 @@
import { Grid } from "@/components";
export const GridDetail_4_8 = ({
label,
value,
}: {
label: React.ReactNode;
value: React.ReactNode;
}) => {
return (
<Grid>
<Grid.Col span={4} style={{ justifyContent: "center", paddingRight: 10 }}>
{label}
</Grid.Col>
<Grid.Col span={8} style={{ justifyContent: "center" }}>
{value}
</Grid.Col>
</Grid>
);
};

View File

@@ -0,0 +1,27 @@
import { Grid } from "@/components";
export const GridSpan_4_8 = ({
label,
value,
}: {
label: React.ReactNode;
value: React.ReactNode;
}) => {
return (
<Grid>
<Grid.Col
span={4}
style={{
justifyContent: "flex-start",
paddingRight: 8,
paddingLeft: 8,
}}
>
{label}
</Grid.Col>
<Grid.Col span={8} style={{ justifyContent: "center", paddingRight: 8 }}>
{value}
</Grid.Col>
</Grid>
);
};

View File

@@ -39,7 +39,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>12</string>
<string>13</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSMinimumSystemVersion</key>

108
utils/badWordsIndonesia.ts Normal file
View File

@@ -0,0 +1,108 @@
// badWordsIndonesia.js (Versi Lengkap)
const badWordsIndonesia = [
// 🐶 Kata Kasar & Vulgar
'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',
// 🔥 Kata Sindiran & Penghinaan
'bego', 'dungu', 'edan', 'gila', 'goblog', 'kampang', 'kampret', 'keparat', 'lonte',
'main mata', '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',
'pengecutt', 'penipuu', 'sintting',
// ⚖️ Kata SARA & Diskriminasi
'cina', 'kafir', 'kampungan', 'kacung', 'mampus', 'menghina', 'racist', 'sara',
'setan', 'syiah', 'waria', 'wong jowo', 'wong sunda', 'wong madura',
'chinna', 'kafiir', 'kampungann', 'kacungg', 'mampuss', 'menghinna', 'racisst',
'saraa', 'setann', 'syiahh', 'wariia', 'wong jowoo', 'wong sundaa', 'wong maduraa',
// 💸 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',
'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',
// 🧩 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',
// 📱 Variasi dengan Angka & Simbol
'4nj1ng', 'b4b1', 'b4ngs4t', 'g0bl0k', 'k0nt0l', 'm3m3k', 'ng3nt0t', 'p3l3r',
't4i', 't0l0l', 'j4nc0k', 'j3mbut', 'k4mpr3t', 's14l4n', 'w1bu',
'4nj1ngg', 'b4b11', 'b4ngs4tt', 'g0bl0kk', 'k0nt0ll', 'm3m3kk', 'ng3nt0tt',
'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',
// 🚫 Kata yang Mengandung Unsur Seksual
'porno', 'seks', 'mesum', 'bugil', 'telanjang', 'payudara', 'pantat', 'vagina', 'penis',
'pornoo', 'sekss', 'mesumm', 'bugill', 'telanjangg', 'payudaraa', 'pantatt', 'vaginna',
'peniss', 'pornoografi', 'pornografi', 'porno graf i', 'seksual', 'seksualitas',
'pornoograffii', 'pornografffii', 'porno graf ii', 'seksuall', 'seksualitass',
// 🤬 Kata Kasar dari Bahasa Daerah (Sunda, Jawa, dll)
'kampret', 'kacung', 'mampus', 'sialan', 'bangsat', 'goblok', 'bodoh', 'tolol',
'kamprett', 'kacungg', 'mampuss', 'sialann', 'bangsaatt', 'gobllokk', 'bodooh', 'tololl',
'kampret sunda', 'kacung jawa', 'mampus batak', 'sialan minang', 'bangsat lampung',
'goblok palembang', 'bodoh medan', 'tolol makassar',
// 📉 Kata yang Sering Digunakan untuk Menjelekkan Orang
// 'jelek', 'buruk', 'tidak pantas', 'tidak sopan', 'tidak beretika', 'tidak beradab',
// 'jelekk', 'burukk', 'tidak pantass', 'tidak sopann', 'tidak beretikaa', 'tidak beradabb',
// 'jelek banget', 'buruk banget', 'tidak pantas banget', 'tidak sopan banget',
// 'tidak beretika banget', 'tidak beradab banget',
// 🛑 Kata yang Sering Digunakan untuk Menyebarkan Hoax
// 'hoax', 'bohong', 'palsu', 'tipu', 'menipu', 'menyesatkan', 'menjerumuskan',
// 'hoaxx', 'bohongg', 'palsuu', 'tipuu', 'menipuu', 'menyesatkanng', 'menjerumuskanng',
// 'hoax besar', 'bohong besar', 'palsu besar', 'tipu besar', 'menipu besar',
// 'menyesatkan besar', 'menjerumuskan besar'
];
// Normalisasi teks
const normalizeText = (text: string) => {
return text.toLowerCase().replace(/\s+/g, ' ').trim();
};
// Cek apakah teks mengandung kata buruk
const isBadContent = (text: string) => {
const normalized = normalizeText(text);
for (let word of badWordsIndonesia) {
if (normalized.includes(word)) {
return true;
}
}
return false;
};
// Saring teks (ganti dengan asterisk)
const censorText = (text: string) => {
let result = text;
for (let word of badWordsIndonesia) {
const regex = new RegExp(word.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'gi');
result = result.replace(regex, '*'.repeat(word.length));
}
return result;
};
export {
badWordsIndonesia,
isBadContent,
censorText,
normalizeText
};