Compare commits
4 Commits
fix-maps/2
...
clean-code
| Author | SHA1 | Date | |
|---|---|---|---|
| a5026cc285 | |||
| 836ef709d2 | |||
| 3bbee15c3a | |||
| ad7dbaf162 |
@@ -21,7 +21,7 @@ export default {
|
||||
"Aplikasi membutuhkan akses lokasi untuk menampilkan peta.",
|
||||
},
|
||||
associatedDomains: ["applinks:cld-dkr-staging-hipmi.wibudev.com"],
|
||||
buildNumber: "1",
|
||||
buildNumber: "3",
|
||||
},
|
||||
|
||||
android: {
|
||||
|
||||
@@ -1,66 +1,93 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import { BasicWrapper, StackCustom, ViewWrapper } from "@/components";
|
||||
import CustomSkeleton from "@/components/_ShareComponent/SkeletonCustom";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import { useNotificationStore } from "@/hooks/use-notification-store";
|
||||
import Home_BottomFeatureSection from "@/screens/Home/bottomFeatureSection";
|
||||
import HeaderBell from "@/screens/Home/HeaderBell";
|
||||
import { stylesHome } from "@/screens/Home/homeViewStyle";
|
||||
import Home_ImageSection from "@/screens/Home/imageSection";
|
||||
import TabSection from "@/screens/Home/tabSection";
|
||||
import { tabsHome } from "@/screens/Home/tabsList";
|
||||
import Home_FeatureSection from "@/screens/Home/topFeatureSection";
|
||||
import { apiJobGetAll } from "@/service/api-client/api-job";
|
||||
import { apiUser } from "@/service/api-client/api-user";
|
||||
import { apiVersion } from "@/service/api-config";
|
||||
import { GStyles } from "@/styles/global-styles";
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
import { Redirect, router, Stack, useFocusEffect } from "expo-router";
|
||||
import { useCallback, useState } from "react";
|
||||
import { RefreshControl } from "react-native";
|
||||
import { RefreshControl, View } from "react-native";
|
||||
|
||||
export default function Application() {
|
||||
const { token, user, userData } = useAuth();
|
||||
const [data, setData] = useState<any>();
|
||||
const [refreshing, setRefreshing] = useState(false);
|
||||
const { syncUnreadCount } = useNotificationStore();
|
||||
const [listData, setListData] = useState<any[] | null>(null);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadData();
|
||||
onLoadDataJob();
|
||||
checkVersion();
|
||||
userData(token as string);
|
||||
userData(token as string).catch((error) => {
|
||||
console.log("[ERROR userData]", error?.message);
|
||||
console.log("[ERROR userData Response]", error?.response?.data);
|
||||
});
|
||||
syncUnreadCount();
|
||||
}, [user?.id, token]),
|
||||
);
|
||||
|
||||
async function onLoadData() {
|
||||
const response = await apiUser(user?.id as string);
|
||||
console.log(
|
||||
"[Profile ID]>>",
|
||||
JSON.stringify(response?.data?.Profile?.id, null, 2),
|
||||
);
|
||||
|
||||
setData(response.data);
|
||||
try {
|
||||
const response = await apiUser(user?.id as string);
|
||||
setData(response.data);
|
||||
} catch (error: any) {
|
||||
console.log("[ERROR onLoadData]", error?.message);
|
||||
console.log("[ERROR Response]", error?.response?.data);
|
||||
// Set data tetap agar UI tidak stuck di loading
|
||||
setData(null);
|
||||
}
|
||||
}
|
||||
|
||||
const onLoadDataJob = async () => {
|
||||
try {
|
||||
const response = await apiJobGetAll({
|
||||
category: "beranda",
|
||||
});
|
||||
const result = response.data
|
||||
.sort(
|
||||
(a: any, b: any) =>
|
||||
new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(),
|
||||
)
|
||||
.slice(0, 2);
|
||||
setListData(result);
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
}
|
||||
};
|
||||
const checkVersion = async () => {
|
||||
const response = await apiVersion();
|
||||
console.log("[Version] >>", JSON.stringify(response.data, null, 2));
|
||||
try {
|
||||
const response = await apiVersion();
|
||||
console.log("[Version] >>", JSON.stringify(response.data, null, 2));
|
||||
} catch (error: any) {
|
||||
console.log("[ERROR checkVersion]", error?.message);
|
||||
}
|
||||
};
|
||||
|
||||
const onRefresh = useCallback(() => {
|
||||
setRefreshing(true);
|
||||
onLoadData();
|
||||
onLoadDataJob();
|
||||
checkVersion();
|
||||
setRefreshing(false);
|
||||
}, []);
|
||||
|
||||
// if (user && user?.termsOfServiceAccepted === false) {
|
||||
// console.log("User is not accept term service");
|
||||
// return <Redirect href={`/terms-agreement`} />;
|
||||
// }
|
||||
|
||||
if (data && data?.active === false) {
|
||||
console.log("User is not active");
|
||||
console.warn("User is not active");
|
||||
return (
|
||||
<BasicWrapper>
|
||||
<Redirect href={`/waiting-room`} />
|
||||
@@ -69,7 +96,7 @@ export default function Application() {
|
||||
}
|
||||
|
||||
if (data && data?.Profile === null) {
|
||||
console.log("Profile is null");
|
||||
console.warn("Profile is null");
|
||||
return (
|
||||
<BasicWrapper>
|
||||
<Redirect href={`/profile/create`} />
|
||||
@@ -91,17 +118,25 @@ export default function Application() {
|
||||
<Stack.Screen
|
||||
options={{
|
||||
title: `HIPMI`,
|
||||
headerLeft: () => (
|
||||
<Ionicons
|
||||
name="search"
|
||||
size={20}
|
||||
color={MainColor.yellow}
|
||||
onPress={() => {
|
||||
router.push("/user-search");
|
||||
}}
|
||||
/>
|
||||
),
|
||||
headerRight: () => <HeaderBell />,
|
||||
headerLeft: () =>
|
||||
data ? (
|
||||
<Ionicons
|
||||
name="search"
|
||||
size={20}
|
||||
color={MainColor.yellow}
|
||||
onPress={() => {
|
||||
router.push("/user-search");
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<CustomSkeleton height={30} width={30} radius={100} />
|
||||
),
|
||||
headerRight: () =>
|
||||
data ? (
|
||||
<HeaderBell />
|
||||
) : (
|
||||
<CustomSkeleton height={30} width={30} radius={100} />
|
||||
),
|
||||
}}
|
||||
/>
|
||||
<ViewWrapper
|
||||
@@ -114,25 +149,51 @@ export default function Application() {
|
||||
/>
|
||||
}
|
||||
footerComponent={
|
||||
<TabSection
|
||||
|
||||
tabs={tabsHome({
|
||||
acceptedForumTermsAt: data?.acceptedForumTermsAt,
|
||||
profileId: data?.Profile?.id,
|
||||
})}
|
||||
/>
|
||||
data && data ? (
|
||||
<TabSection
|
||||
tabs={tabsHome({
|
||||
acceptedForumTermsAt: data?.acceptedForumTermsAt,
|
||||
profileId: data?.Profile?.id,
|
||||
})}
|
||||
/>
|
||||
) : (
|
||||
<View style={GStyles.tabBar}>
|
||||
<View style={[GStyles.tabContainer, { paddingTop: 10 }]}>
|
||||
{Array.from({ length: 4 }).map((e, index) => (
|
||||
<CustomSkeleton
|
||||
key={index}
|
||||
height={40}
|
||||
width={40}
|
||||
radius={100}
|
||||
/>
|
||||
))}
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
>
|
||||
<StackCustom>
|
||||
{/* <ButtonCustom onPress={() => router.push("./test-notifications")}>
|
||||
Test Notif
|
||||
</ButtonCustom> */}
|
||||
|
||||
<Home_ImageSection />
|
||||
|
||||
<Home_FeatureSection />
|
||||
{data && data ? (
|
||||
<Home_FeatureSection />
|
||||
) : (
|
||||
<View style={stylesHome.gridContainer}>
|
||||
{Array.from({ length: 4 }).map((item, index) => (
|
||||
<CustomSkeleton
|
||||
key={index}
|
||||
style={stylesHome.gridItem}
|
||||
radius={50}
|
||||
/>
|
||||
))}
|
||||
</View>
|
||||
)}
|
||||
|
||||
<Home_BottomFeatureSection />
|
||||
{data ? (
|
||||
<Home_BottomFeatureSection listData={listData} />
|
||||
) : (
|
||||
<CustomSkeleton height={200} />
|
||||
)}
|
||||
</StackCustom>
|
||||
</ViewWrapper>
|
||||
</>
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
} from "@/components";
|
||||
import LeftButtonCustom from "@/components/Button/BackButton";
|
||||
import GridTwoView from "@/components/_ShareComponent/GridTwoView";
|
||||
import CustomSkeleton from "@/components/_ShareComponent/SkeletonCustom";
|
||||
import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import { ICON_SIZE_SMALL } from "@/constants/constans-value";
|
||||
@@ -64,6 +65,8 @@ export default function Portofolio() {
|
||||
setProfileId(response?.data?.Profile?.id);
|
||||
};
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Header */}
|
||||
@@ -87,7 +90,10 @@ export default function Portofolio() {
|
||||
/>
|
||||
<ViewWrapper>
|
||||
{!data || !profileId ? (
|
||||
<LoaderCustom />
|
||||
<StackCustom>
|
||||
<CustomSkeleton height={400} />
|
||||
<CustomSkeleton height={300} />
|
||||
</StackCustom>
|
||||
) : (
|
||||
<StackCustom>
|
||||
<Portofolio_Data
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import { LoaderCustom } from "@/components";
|
||||
import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
|
||||
import { NewWrapper, StackCustom } from "@/components";
|
||||
import CustomSkeleton from "@/components/_ShareComponent/SkeletonCustom";
|
||||
import LeftButtonCustom from "@/components/Button/BackButton";
|
||||
import DrawerCustom from "@/components/Drawer/DrawerCustom";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
@@ -16,8 +16,8 @@ import { GStyles } from "@/styles/global-styles";
|
||||
import { IProfile } from "@/types/Type-Profile";
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
import { Stack, useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import React, { useCallback, useState } from "react";
|
||||
import { TouchableOpacity } from "react-native";
|
||||
import { useCallback, useState } from "react";
|
||||
import { RefreshControl, TouchableOpacity } from "react-native";
|
||||
|
||||
export default function Profile() {
|
||||
const { id } = useLocalSearchParams();
|
||||
@@ -25,6 +25,7 @@ export default function Profile() {
|
||||
const [data, setData] = useState<IProfile>();
|
||||
const [dataToken, setDataToken] = useState<IProfile>();
|
||||
const [listPortofolio, setListPortofolio] = useState<any[]>();
|
||||
const [refreshing, setRefreshing] = useState(false);
|
||||
|
||||
const { token, logout, isAdmin, user, userData } = useAuth();
|
||||
|
||||
@@ -43,7 +44,7 @@ export default function Profile() {
|
||||
onLoadUserByToken();
|
||||
isUserCheck();
|
||||
userData(token as string);
|
||||
}, [id, token])
|
||||
}, [id, token]),
|
||||
);
|
||||
|
||||
const isUserCheck = () => {
|
||||
@@ -54,13 +55,21 @@ export default function Profile() {
|
||||
};
|
||||
|
||||
const onLoadData = async (id: string) => {
|
||||
const response = await apiProfile({ id: id });
|
||||
setData(response.data);
|
||||
try {
|
||||
const response = await apiProfile({ id: id });
|
||||
setData(response.data);
|
||||
} catch (error) {
|
||||
console.log("[ERROR onLoadData]", error);
|
||||
}
|
||||
};
|
||||
|
||||
const onLoadUserByToken = async () => {
|
||||
const response = await apiUser(user?.id as string);
|
||||
setDataToken(response?.data?.Profile);
|
||||
try {
|
||||
const response = await apiUser(user?.id as string);
|
||||
setDataToken(response?.data?.Profile);
|
||||
} catch (error) {
|
||||
console.log("[ERROR onLoadUserByToken]", error);
|
||||
}
|
||||
};
|
||||
|
||||
const onLoadPortofolio = async (id: string) => {
|
||||
@@ -69,15 +78,25 @@ export default function Profile() {
|
||||
const lastTwoByDate = response.data
|
||||
.sort(
|
||||
(a: any, b: any) =>
|
||||
new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()
|
||||
new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(),
|
||||
) // urut desc
|
||||
.slice(0, 2);
|
||||
setListPortofolio(lastTwoByDate);
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
console.log("[ERROR onLoadPortofolio]", error);
|
||||
}
|
||||
};
|
||||
|
||||
const onRefresh = useCallback(() => {
|
||||
setRefreshing(true);
|
||||
onLoadData(id as string);
|
||||
onLoadPortofolio(id as string);
|
||||
onLoadUserByToken();
|
||||
isUserCheck();
|
||||
userData(token as string);
|
||||
setRefreshing(false);
|
||||
}, [id, token]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Stack.Screen
|
||||
@@ -97,9 +116,21 @@ export default function Profile() {
|
||||
}}
|
||||
/>
|
||||
{/* Main View */}
|
||||
<ViewWrapper>
|
||||
<NewWrapper
|
||||
refreshControl={
|
||||
<RefreshControl
|
||||
refreshing={refreshing}
|
||||
onRefresh={onRefresh}
|
||||
tintColor={MainColor.yellow}
|
||||
colors={[MainColor.yellow]}
|
||||
/>
|
||||
}
|
||||
>
|
||||
{!data || !dataToken ? (
|
||||
<LoaderCustom />
|
||||
<StackCustom>
|
||||
<CustomSkeleton height={400} />
|
||||
<CustomSkeleton height={200} />
|
||||
</StackCustom>
|
||||
) : (
|
||||
<>
|
||||
<ProfileSection data={data as any} />
|
||||
@@ -110,7 +141,7 @@ export default function Profile() {
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</ViewWrapper>
|
||||
</NewWrapper>
|
||||
|
||||
{/* Drawer Komponen Eksternal */}
|
||||
<DrawerCustom
|
||||
|
||||
@@ -1,254 +1,5 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import {
|
||||
ActionIcon,
|
||||
AlertDefaultSystem,
|
||||
BadgeCustom,
|
||||
BaseBox,
|
||||
DrawerCustom,
|
||||
LoaderCustom,
|
||||
MenuDrawerDynamicGrid,
|
||||
Spacing,
|
||||
StackCustom,
|
||||
TextCustom,
|
||||
ViewWrapper,
|
||||
} from "@/components";
|
||||
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 { 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";
|
||||
import { funUpdateStatusEvent } from "@/screens/Admin/Event/funUpdateStatus";
|
||||
import { apiAdminEventById } from "@/service/api-admin/api-admin-event";
|
||||
import { DEEP_LINK_URL } from "@/service/api-config";
|
||||
import { colorBadgeStatus } from "@/utils/colorBadge";
|
||||
import { dateTimeView } from "@/utils/dateTimeView";
|
||||
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import React, { useCallback } from "react";
|
||||
import QRCode from "react-native-qrcode-svg";
|
||||
import Toast from "react-native-toast-message";
|
||||
import { Admin_ScreenEventDetail } from "@/screens/Admin/Event/ScreenEventDetail";
|
||||
|
||||
export default function AdminEventDetail() {
|
||||
const { user } = useAuth();
|
||||
const { id, status } = useLocalSearchParams();
|
||||
const [openDrawer, setOpenDrawer] = React.useState(false);
|
||||
|
||||
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();
|
||||
}, [id])
|
||||
);
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
setLoadData(true);
|
||||
const response = await apiAdminEventById({
|
||||
id: id as string,
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
setData(response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
setLoadData(false);
|
||||
}
|
||||
};
|
||||
|
||||
const listData = [
|
||||
{
|
||||
label: "Pembuat Event",
|
||||
value: (data && data?.Author?.username) || "-",
|
||||
},
|
||||
{
|
||||
label: "Judul Event",
|
||||
value: (data && data?.title) || "-",
|
||||
},
|
||||
{
|
||||
label: "Status",
|
||||
value:
|
||||
(data && (
|
||||
<BadgeCustom color={colorBadgeStatus({ status: status as string })}>
|
||||
{_.startCase(status as string)}
|
||||
</BadgeCustom>
|
||||
)) ||
|
||||
"-",
|
||||
},
|
||||
{
|
||||
label: "Lokasi",
|
||||
value: (data && data?.lokasi) || "-",
|
||||
},
|
||||
{
|
||||
label: "Tipe Acara",
|
||||
value: (data && data?.EventMaster_TipeAcara?.name) || "-",
|
||||
},
|
||||
{
|
||||
label: "Mulai Event",
|
||||
value:
|
||||
(data && data?.tanggal && dateTimeView({ date: data?.tanggal })) || "-",
|
||||
},
|
||||
{
|
||||
label: "Event Berakhir",
|
||||
value:
|
||||
(data &&
|
||||
data?.tanggalSelesai &&
|
||||
dateTimeView({ date: data?.tanggalSelesai })) ||
|
||||
"-",
|
||||
},
|
||||
{
|
||||
label: "Deskripsi",
|
||||
value: (data && data?.deskripsi) || "-",
|
||||
},
|
||||
];
|
||||
|
||||
const rightComponent = (
|
||||
<ActionIcon
|
||||
icon={<IconDot size={ICON_SIZE_BUTTON} />}
|
||||
onPress={() => {
|
||||
setOpenDrawer(true);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
const handlerSubmit = async () => {
|
||||
try {
|
||||
const response = await funUpdateStatusEvent({
|
||||
id: id as string,
|
||||
changeStatus: "publish",
|
||||
data: { catatan: "", senderId: user?.id as string },
|
||||
});
|
||||
|
||||
if (!response.success) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: "Gagal mempublikasikan event",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: "Event berhasil dipublikasikan",
|
||||
});
|
||||
router.back();
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ViewWrapper
|
||||
headerComponent={
|
||||
<AdminBackButtonAntTitle
|
||||
title={`Detail Data`}
|
||||
rightComponent={
|
||||
(status === "publish" || status === "history") && rightComponent
|
||||
}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<BaseBox>
|
||||
<StackCustom>
|
||||
{listData.map((item, i) => (
|
||||
<GridSpan_4_8
|
||||
key={i}
|
||||
label={<TextCustom bold>{item.label}</TextCustom>}
|
||||
value={<TextCustom>{item.value}</TextCustom>}
|
||||
/>
|
||||
))}
|
||||
</StackCustom>
|
||||
|
||||
<Spacing />
|
||||
</BaseBox>
|
||||
|
||||
{data &&
|
||||
data?.catatan &&
|
||||
(status === "reject" || status === "review") && (
|
||||
<ReportBox text={data?.catatan} />
|
||||
)}
|
||||
|
||||
{(status === "publish" || status === "history") && (
|
||||
<BaseBox>
|
||||
<StackCustom style={{ alignItems: "center" }}>
|
||||
<TextCustom bold>QR Code Event</TextCustom>
|
||||
{loadData ? (
|
||||
<LoaderCustom />
|
||||
) : (
|
||||
<QRCode
|
||||
value={isDevLink}
|
||||
size={200}
|
||||
// logo={require("@/assets/images/logo-hipmi.png")}
|
||||
// logoSize={70}
|
||||
// logoBackgroundColor="transparent"
|
||||
// logoBorderRadius={50}
|
||||
// color="black"
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* <TextCustom align="center">{isDevLink}</TextCustom> */}
|
||||
</StackCustom>
|
||||
</BaseBox>
|
||||
)}
|
||||
|
||||
{status === "review" && (
|
||||
<AdminButtonReview
|
||||
onPublish={() => {
|
||||
AlertDefaultSystem({
|
||||
title: "Publish",
|
||||
message: "Apakah anda yakin ingin mempublikasikan data ini?",
|
||||
textLeft: "Batal",
|
||||
textRight: "Ya",
|
||||
onPressRight: () => handlerSubmit(),
|
||||
});
|
||||
}}
|
||||
onReject={() => {
|
||||
router.push(`/admin/event/${id}/reject-input?status=${status}`);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{status === "reject" && (
|
||||
<AdminButtonReject
|
||||
title="Tambah Catatan"
|
||||
onReject={() => {
|
||||
router.push(`/admin/event/${id}/reject-input?status=${status}`);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<Spacing />
|
||||
</ViewWrapper>
|
||||
|
||||
<DrawerCustom
|
||||
isVisible={openDrawer}
|
||||
closeDrawer={() => setOpenDrawer(false)}
|
||||
height={"auto"}
|
||||
>
|
||||
<MenuDrawerDynamicGrid
|
||||
data={[
|
||||
{
|
||||
label: "Daftar Peserta",
|
||||
icon: <IconList />,
|
||||
path: `/admin/event/${id}/list-of-participants`,
|
||||
},
|
||||
]}
|
||||
onPressItem={(item) => {
|
||||
setOpenDrawer(false);
|
||||
router.push(item.path as any);
|
||||
}}
|
||||
/>
|
||||
</DrawerCustom>
|
||||
</>
|
||||
);
|
||||
return <Admin_ScreenEventDetail />;
|
||||
}
|
||||
|
||||
@@ -9,32 +9,14 @@ import {
|
||||
ViewWrapper,
|
||||
} from "@/components";
|
||||
import GridTwoView from "@/components/_ShareComponent/GridTwoView";
|
||||
import API_IMAGE from "@/constants/api-storage";
|
||||
import { MapMarker, MapsV2Custom } from "@/components/Map/MapsV2Custom";
|
||||
import { ICON_SIZE_SMALL } from "@/constants/constans-value";
|
||||
import { apiMapsGetAll } from "@/service/api-client/api-maps";
|
||||
import { openInDeviceMaps } from "@/utils/openInDeviceMaps";
|
||||
import { FontAwesome, Ionicons } from "@expo/vector-icons";
|
||||
import { Image } from "expo-image";
|
||||
import { router, useFocusEffect } from "expo-router";
|
||||
import { useCallback, useState } from "react";
|
||||
import { View } from "react-native";
|
||||
import MapView, { Marker } from "react-native-maps";
|
||||
|
||||
const defaultRegion = {
|
||||
latitude: -8.737109,
|
||||
longitude: 115.1756897,
|
||||
latitudeDelta: 0.1,
|
||||
longitudeDelta: 0.1,
|
||||
height: 300,
|
||||
};
|
||||
|
||||
export interface LocationItem {
|
||||
id: string | number;
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
name: string;
|
||||
imageId?: string;
|
||||
}
|
||||
export default function AdminMaps() {
|
||||
const [list, setList] = useState<any[] | null>(null);
|
||||
const [loadList, setLoadList] = useState(false);
|
||||
@@ -72,74 +54,30 @@ export default function AdminMaps() {
|
||||
}
|
||||
};
|
||||
|
||||
const markers: MapMarker[] = list?.map((item) => ({
|
||||
id: item.id,
|
||||
coordinate: [item.longitude, item.latitude] as [number, number],
|
||||
imageId: item.Portofolio?.logoId,
|
||||
onSelected: () => {
|
||||
setOpenDrawer(true);
|
||||
setSelected({
|
||||
id: item?.id,
|
||||
bidangBisnis: item?.Portofolio?.MasterBidangBisnis?.name,
|
||||
nomorTelepon: item?.Portofolio?.tlpn,
|
||||
alamatBisnis: item?.Portofolio?.alamatKantor,
|
||||
namePin: item?.namePin,
|
||||
imageId: item?.imageId,
|
||||
portofolioId: item?.Portofolio?.id,
|
||||
latitude: item?.latitude,
|
||||
longitude: item?.longitude,
|
||||
});
|
||||
},
|
||||
})) || [];
|
||||
|
||||
return (
|
||||
<>
|
||||
<ViewWrapper style={{ paddingInline: 0, paddingBlock: 0 }}>
|
||||
{/* <MapCustom height={"100%"} /> */}
|
||||
<View style={{ flex: 1 }}>
|
||||
{loadList ? (
|
||||
<MapView
|
||||
initialRegion={defaultRegion}
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<MapView
|
||||
initialRegion={defaultRegion}
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
}}
|
||||
>
|
||||
{list?.map((item: any, index: number) => {
|
||||
return (
|
||||
<Marker
|
||||
key={item?.id}
|
||||
coordinate={{
|
||||
latitude: item?.latitude,
|
||||
longitude: item?.longitude,
|
||||
}}
|
||||
title={item?.namePin}
|
||||
onPress={() => {
|
||||
setOpenDrawer(true);
|
||||
setSelected({
|
||||
id: item?.id,
|
||||
bidangBisnis:
|
||||
item?.Portofolio?.MasterBidangBisnis?.name,
|
||||
nomorTelepon: item?.Portofolio?.tlpn,
|
||||
alamatBisnis: item?.Portofolio?.alamatKantor,
|
||||
namePin: item?.namePin,
|
||||
imageId: item?.imageId,
|
||||
portofolioId: item?.Portofolio?.id,
|
||||
latitude: item?.latitude,
|
||||
longitude: item?.longitude,
|
||||
});
|
||||
}}
|
||||
// Gunakan gambar kustom jika tersedia
|
||||
>
|
||||
<View>
|
||||
<Image
|
||||
source={{
|
||||
uri: API_IMAGE.GET({
|
||||
fileId: item?.Portofolio?.logoId,
|
||||
}),
|
||||
}}
|
||||
style={{
|
||||
width: 30,
|
||||
height: 30,
|
||||
borderRadius: 100,
|
||||
borderWidth: 1,
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
</Marker>
|
||||
);
|
||||
})}
|
||||
</MapView>
|
||||
)}
|
||||
</View>
|
||||
<MapsV2Custom markers={markers} />
|
||||
</ViewWrapper>
|
||||
|
||||
<DrawerCustom
|
||||
@@ -147,7 +85,9 @@ export default function AdminMaps() {
|
||||
closeDrawer={() => setOpenDrawer(false)}
|
||||
height={"auto"}
|
||||
>
|
||||
<DummyLandscapeImage height={200} imageId={selected.imageId} />
|
||||
{selected.imageId && (
|
||||
<DummyLandscapeImage height={200} imageId={selected.imageId} />
|
||||
)}
|
||||
<Spacing />
|
||||
<StackCustom gap={"xs"}>
|
||||
<GridTwoView
|
||||
|
||||
@@ -77,8 +77,12 @@ export default function NotificationInitializer() {
|
||||
});
|
||||
|
||||
console.log("✅ Device token berhasil didaftarkan ke backend");
|
||||
} catch (error) {
|
||||
console.error("❌ Gagal mendaftarkan device token:", error);
|
||||
} catch (error: any) {
|
||||
// Log error detail tapi jangan crash aplikasi
|
||||
console.error("❌ Gagal mendaftarkan device token:", error?.message);
|
||||
console.error("Response status:", error?.response?.status);
|
||||
console.error("Response data:", error?.response?.data);
|
||||
// Skip logout - biarkan user tetap bisa pakai app meski notif gagal
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ const CustomSkeleton: React.FC<CustomSkeletonProps> = ({
|
||||
right: 0,
|
||||
height: 100,
|
||||
backgroundColor: MainColor.soft_darkblue,
|
||||
borderRadius: 4,
|
||||
borderRadius: 1,
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
|
||||
@@ -55,10 +55,10 @@ Component yang digunakan: components/_ShareComponent/NewWrapper.tsx
|
||||
|
||||
<!-- START Prompt Admin Refactoring -->
|
||||
<!-- Pindah kode ke Screen Component -->
|
||||
File source: app/(application)/admin/forum/[id]/list-comment.tsx
|
||||
Folder tujuan: screens/Admin/Forum
|
||||
Nama file utama: ScreenForumListComment.tsx
|
||||
Nama function utama: Admin_ScreenForumListComment
|
||||
File source: app/(application)/admin/event/[id]/[status]/index.tsx
|
||||
Folder tujuan: screens/Admin/Event
|
||||
Nama file utama: ScreenEventDetail.tsx
|
||||
Nama function utama: Admin_ScreenEventDetail
|
||||
File komponen wrapper: components/_ShareComponent/NewWrapper.tsx
|
||||
|
||||
Buat file baru pada "Folder tujuan" dengan nama "Nama file utama" dan ubah nama function menjadi "Nama function utama" kemudian clean code, import dan panggil function tersebut pada file "File source"
|
||||
|
||||
@@ -171,6 +171,18 @@
|
||||
EEC6AC8AF9C04E91AA81C190 /* Remove signature files (Xcode workaround) */,
|
||||
D2BED766D85C4781B154BD69 /* Remove signature files (Xcode workaround) */,
|
||||
E01278D305D540D5B29ED50A /* Remove signature files (Xcode workaround) */,
|
||||
72EDC26CA2144B90BEFE947F /* Remove signature files (Xcode workaround) */,
|
||||
0A09E19272A94BEBAAF5A27A /* Remove signature files (Xcode workaround) */,
|
||||
9B007D2599C64C7F8F525B86 /* Remove signature files (Xcode workaround) */,
|
||||
1393AE9C86924FA8B1F8D11E /* Remove signature files (Xcode workaround) */,
|
||||
E1F9AE3DCABE4A088A05E180 /* Remove signature files (Xcode workaround) */,
|
||||
211F6E22A1B24524B67693F8 /* Remove signature files (Xcode workaround) */,
|
||||
469F2CAA8928481CA86EB0F4 /* Remove signature files (Xcode workaround) */,
|
||||
0F9297956F4F4FC9881920F8 /* Remove signature files (Xcode workaround) */,
|
||||
058D2457CFA64FD9AC31C74F /* Remove signature files (Xcode workaround) */,
|
||||
FB0CB57BF4D74C1D87C2036C /* Remove signature files (Xcode workaround) */,
|
||||
14B3DE54EE4049AEB1EADA6B /* Remove signature files (Xcode workaround) */,
|
||||
B4CF5E09DBB44A4FB9CB91B9 /* Remove signature files (Xcode workaround) */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -779,6 +791,210 @@
|
||||
rm -rf \"$CONFIGURATION_BUILD_DIR/MapLibre.xcframework-ios.signature\";
|
||||
";
|
||||
};
|
||||
72EDC26CA2144B90BEFE947F /* Remove signature files (Xcode workaround) */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
name = "Remove signature files (Xcode workaround)";
|
||||
inputPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "
|
||||
echo \"Remove signature files (Xcode workaround)\";
|
||||
rm -rf \"$CONFIGURATION_BUILD_DIR/MapLibre.xcframework-ios.signature\";
|
||||
";
|
||||
};
|
||||
0A09E19272A94BEBAAF5A27A /* Remove signature files (Xcode workaround) */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
name = "Remove signature files (Xcode workaround)";
|
||||
inputPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "
|
||||
echo \"Remove signature files (Xcode workaround)\";
|
||||
rm -rf \"$CONFIGURATION_BUILD_DIR/MapLibre.xcframework-ios.signature\";
|
||||
";
|
||||
};
|
||||
9B007D2599C64C7F8F525B86 /* Remove signature files (Xcode workaround) */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
name = "Remove signature files (Xcode workaround)";
|
||||
inputPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "
|
||||
echo \"Remove signature files (Xcode workaround)\";
|
||||
rm -rf \"$CONFIGURATION_BUILD_DIR/MapLibre.xcframework-ios.signature\";
|
||||
";
|
||||
};
|
||||
1393AE9C86924FA8B1F8D11E /* Remove signature files (Xcode workaround) */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
name = "Remove signature files (Xcode workaround)";
|
||||
inputPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "
|
||||
echo \"Remove signature files (Xcode workaround)\";
|
||||
rm -rf \"$CONFIGURATION_BUILD_DIR/MapLibre.xcframework-ios.signature\";
|
||||
";
|
||||
};
|
||||
E1F9AE3DCABE4A088A05E180 /* Remove signature files (Xcode workaround) */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
name = "Remove signature files (Xcode workaround)";
|
||||
inputPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "
|
||||
echo \"Remove signature files (Xcode workaround)\";
|
||||
rm -rf \"$CONFIGURATION_BUILD_DIR/MapLibre.xcframework-ios.signature\";
|
||||
";
|
||||
};
|
||||
211F6E22A1B24524B67693F8 /* Remove signature files (Xcode workaround) */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
name = "Remove signature files (Xcode workaround)";
|
||||
inputPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "
|
||||
echo \"Remove signature files (Xcode workaround)\";
|
||||
rm -rf \"$CONFIGURATION_BUILD_DIR/MapLibre.xcframework-ios.signature\";
|
||||
";
|
||||
};
|
||||
469F2CAA8928481CA86EB0F4 /* Remove signature files (Xcode workaround) */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
name = "Remove signature files (Xcode workaround)";
|
||||
inputPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "
|
||||
echo \"Remove signature files (Xcode workaround)\";
|
||||
rm -rf \"$CONFIGURATION_BUILD_DIR/MapLibre.xcframework-ios.signature\";
|
||||
";
|
||||
};
|
||||
0F9297956F4F4FC9881920F8 /* Remove signature files (Xcode workaround) */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
name = "Remove signature files (Xcode workaround)";
|
||||
inputPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "
|
||||
echo \"Remove signature files (Xcode workaround)\";
|
||||
rm -rf \"$CONFIGURATION_BUILD_DIR/MapLibre.xcframework-ios.signature\";
|
||||
";
|
||||
};
|
||||
058D2457CFA64FD9AC31C74F /* Remove signature files (Xcode workaround) */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
name = "Remove signature files (Xcode workaround)";
|
||||
inputPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "
|
||||
echo \"Remove signature files (Xcode workaround)\";
|
||||
rm -rf \"$CONFIGURATION_BUILD_DIR/MapLibre.xcframework-ios.signature\";
|
||||
";
|
||||
};
|
||||
FB0CB57BF4D74C1D87C2036C /* Remove signature files (Xcode workaround) */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
name = "Remove signature files (Xcode workaround)";
|
||||
inputPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "
|
||||
echo \"Remove signature files (Xcode workaround)\";
|
||||
rm -rf \"$CONFIGURATION_BUILD_DIR/MapLibre.xcframework-ios.signature\";
|
||||
";
|
||||
};
|
||||
14B3DE54EE4049AEB1EADA6B /* Remove signature files (Xcode workaround) */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
name = "Remove signature files (Xcode workaround)";
|
||||
inputPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "
|
||||
echo \"Remove signature files (Xcode workaround)\";
|
||||
rm -rf \"$CONFIGURATION_BUILD_DIR/MapLibre.xcframework-ios.signature\";
|
||||
";
|
||||
};
|
||||
B4CF5E09DBB44A4FB9CB91B9 /* Remove signature files (Xcode workaround) */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
name = "Remove signature files (Xcode workaround)";
|
||||
inputPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "
|
||||
echo \"Remove signature files (Xcode workaround)\";
|
||||
rm -rf \"$CONFIGURATION_BUILD_DIR/MapLibre.xcframework-ios.signature\";
|
||||
";
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<string>3</string>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
|
||||
85
screens/Admin/Event/BoxEventDetail.tsx
Normal file
85
screens/Admin/Event/BoxEventDetail.tsx
Normal file
@@ -0,0 +1,85 @@
|
||||
import { BadgeCustom, BaseBox, Spacing, StackCustom, TextCustom } from "@/components";
|
||||
import { GridSpan_4_8 } from "@/components/_ShareComponent/GridSpan_4_8";
|
||||
import { colorBadgeStatus } from "@/utils/colorBadge";
|
||||
import { dateTimeView } from "@/utils/dateTimeView";
|
||||
import _ from "lodash";
|
||||
|
||||
interface EventDetailData {
|
||||
Author?: {
|
||||
username?: string;
|
||||
};
|
||||
title?: string;
|
||||
lokasi?: string;
|
||||
EventMaster_TipeAcara?: {
|
||||
name?: string;
|
||||
};
|
||||
tanggal?: string;
|
||||
tanggalSelesai?: string;
|
||||
deskripsi?: string;
|
||||
catatan?: string;
|
||||
}
|
||||
|
||||
interface BoxEventDetailProps {
|
||||
data: EventDetailData | null;
|
||||
status: string;
|
||||
}
|
||||
|
||||
export function BoxEventDetail({ data, status }: BoxEventDetailProps) {
|
||||
const listData = [
|
||||
{
|
||||
label: "Pembuat Event",
|
||||
value: data?.Author?.username || "-",
|
||||
},
|
||||
{
|
||||
label: "Judul Event",
|
||||
value: data?.title || "-",
|
||||
},
|
||||
{
|
||||
label: "Status",
|
||||
value: data ? (
|
||||
<BadgeCustom color={colorBadgeStatus({ status })}>
|
||||
{_.startCase(status)}
|
||||
</BadgeCustom>
|
||||
) : (
|
||||
"-"
|
||||
),
|
||||
},
|
||||
{
|
||||
label: "Lokasi",
|
||||
value: data?.lokasi || "-",
|
||||
},
|
||||
{
|
||||
label: "Tipe Acara",
|
||||
value: data?.EventMaster_TipeAcara?.name || "-",
|
||||
},
|
||||
{
|
||||
label: "Mulai Event",
|
||||
value: data?.tanggal ? dateTimeView({ date: data.tanggal }) : "-",
|
||||
},
|
||||
{
|
||||
label: "Event Berakhir",
|
||||
value: data?.tanggalSelesai
|
||||
? dateTimeView({ date: data.tanggalSelesai })
|
||||
: "-",
|
||||
},
|
||||
{
|
||||
label: "Deskripsi",
|
||||
value: data?.deskripsi || "-",
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<BaseBox>
|
||||
<StackCustom>
|
||||
{listData.map((item, i) => (
|
||||
<GridSpan_4_8
|
||||
key={i}
|
||||
label={<TextCustom bold>{item.label}</TextCustom>}
|
||||
value={<TextCustom>{item.value}</TextCustom>}
|
||||
/>
|
||||
))}
|
||||
</StackCustom>
|
||||
<Spacing />
|
||||
</BaseBox>
|
||||
);
|
||||
}
|
||||
37
screens/Admin/Event/EventDetailDrawer.tsx
Normal file
37
screens/Admin/Event/EventDetailDrawer.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import { DrawerCustom, MenuDrawerDynamicGrid } from "@/components";
|
||||
import { IconList } from "@/components/_Icon/IconComponent";
|
||||
import { router } from "expo-router";
|
||||
|
||||
interface EventDetailDrawerProps {
|
||||
isVisible: boolean;
|
||||
onClose: () => void;
|
||||
eventId: string;
|
||||
}
|
||||
|
||||
export function EventDetailDrawer({
|
||||
isVisible,
|
||||
onClose,
|
||||
eventId,
|
||||
}: EventDetailDrawerProps) {
|
||||
return (
|
||||
<DrawerCustom
|
||||
isVisible={isVisible}
|
||||
closeDrawer={onClose}
|
||||
height={"auto"}
|
||||
>
|
||||
<MenuDrawerDynamicGrid
|
||||
data={[
|
||||
{
|
||||
label: "Daftar Peserta",
|
||||
icon: <IconList />,
|
||||
path: `/admin/event/${eventId}/list-of-participants`,
|
||||
},
|
||||
]}
|
||||
onPressItem={(item) => {
|
||||
onClose();
|
||||
router.push(item.path as any);
|
||||
}}
|
||||
/>
|
||||
</DrawerCustom>
|
||||
);
|
||||
}
|
||||
26
screens/Admin/Event/EventDetailQRCode.tsx
Normal file
26
screens/Admin/Event/EventDetailQRCode.tsx
Normal file
@@ -0,0 +1,26 @@
|
||||
import { BaseBox, LoaderCustom, Spacing, StackCustom, TextCustom } from "@/components";
|
||||
import QRCode from "react-native-qrcode-svg";
|
||||
|
||||
interface EventDetailQRCodeProps {
|
||||
qrValue: string;
|
||||
isLoading: boolean;
|
||||
}
|
||||
|
||||
export function EventDetailQRCode({ qrValue, isLoading }: EventDetailQRCodeProps) {
|
||||
return (
|
||||
<BaseBox>
|
||||
<StackCustom style={{ alignItems: "center" }}>
|
||||
<TextCustom bold>QR Code Event</TextCustom>
|
||||
{isLoading ? (
|
||||
<LoaderCustom />
|
||||
) : (
|
||||
<QRCode
|
||||
value={qrValue}
|
||||
size={200}
|
||||
/>
|
||||
)}
|
||||
</StackCustom>
|
||||
<Spacing />
|
||||
</BaseBox>
|
||||
);
|
||||
}
|
||||
163
screens/Admin/Event/ScreenEventDetail.tsx
Normal file
163
screens/Admin/Event/ScreenEventDetail.tsx
Normal file
@@ -0,0 +1,163 @@
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import { ActionIcon, AlertDefaultSystem } from "@/components";
|
||||
import { IconDot } 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 ReportBox from "@/components/Box/ReportBox";
|
||||
import NewWrapper from "@/components/_ShareComponent/NewWrapper";
|
||||
import { ICON_SIZE_BUTTON } from "@/constants/constans-value";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import { funUpdateStatusEvent } from "@/screens/Admin/Event/funUpdateStatus";
|
||||
import { apiAdminEventById } from "@/service/api-admin/api-admin-event";
|
||||
import { DEEP_LINK_URL } from "@/service/api-config";
|
||||
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import { useCallback, useMemo, useState } from "react";
|
||||
import Toast from "react-native-toast-message";
|
||||
import { BoxEventDetail } from "./BoxEventDetail";
|
||||
import { EventDetailDrawer } from "./EventDetailDrawer";
|
||||
import { EventDetailQRCode } from "./EventDetailQRCode";
|
||||
|
||||
export function Admin_ScreenEventDetail() {
|
||||
const { user } = useAuth();
|
||||
const { id, status } = useLocalSearchParams();
|
||||
const [openDrawer, setOpenDrawer] = useState(false);
|
||||
const [data, setData] = useState<any | null>(null);
|
||||
const [loadData, setLoadData] = 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();
|
||||
}, [id]),
|
||||
);
|
||||
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
setLoadData(true);
|
||||
const response = await apiAdminEventById({
|
||||
id: id as string,
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
setData(response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
} finally {
|
||||
setLoadData(false);
|
||||
}
|
||||
};
|
||||
|
||||
const rightComponent = (
|
||||
<ActionIcon
|
||||
icon={<IconDot size={ICON_SIZE_BUTTON} />}
|
||||
onPress={() => {
|
||||
setOpenDrawer(true);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
const handlerSubmit = async () => {
|
||||
try {
|
||||
const response = await funUpdateStatusEvent({
|
||||
id: id as string,
|
||||
changeStatus: "publish",
|
||||
data: { catatan: "", senderId: user?.id as string },
|
||||
});
|
||||
|
||||
if (!response.success) {
|
||||
Toast.show({
|
||||
type: "error",
|
||||
text1: "Gagal mempublikasikan event",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
Toast.show({
|
||||
type: "success",
|
||||
text1: "Event berhasil dipublikasikan",
|
||||
});
|
||||
router.back();
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
}
|
||||
};
|
||||
|
||||
const headerComponent = useMemo(
|
||||
() => (
|
||||
<AdminBackButtonAntTitle
|
||||
title={`Detail Data`}
|
||||
rightComponent={
|
||||
status === "publish" || status === "history"
|
||||
? rightComponent
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
),
|
||||
[status],
|
||||
);
|
||||
|
||||
const footerComponent = useMemo(() => {
|
||||
if (status === "review") {
|
||||
return (
|
||||
<AdminButtonReview
|
||||
onPublish={() => {
|
||||
AlertDefaultSystem({
|
||||
title: "Publish",
|
||||
message: "Apakah anda yakin ingin mempublikasikan data ini?",
|
||||
textLeft: "Batal",
|
||||
textRight: "Ya",
|
||||
onPressRight: () => handlerSubmit(),
|
||||
});
|
||||
}}
|
||||
onReject={() => {
|
||||
router.push(`/admin/event/${id}/reject-input?status=${status}`);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (status === "reject") {
|
||||
return (
|
||||
<AdminButtonReject
|
||||
title="Tambah Catatan"
|
||||
onReject={() => {
|
||||
router.push(`/admin/event/${id}/reject-input?status=${status}`);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}, [status, id]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<NewWrapper
|
||||
headerComponent={headerComponent}
|
||||
footerComponent={footerComponent}
|
||||
>
|
||||
<BoxEventDetail data={data} status={status as string} />
|
||||
|
||||
{data?.catatan && (status === "reject" || status === "review") && (
|
||||
<ReportBox text={data.catatan} />
|
||||
)}
|
||||
|
||||
{(status === "publish" || status === "history") && (
|
||||
<EventDetailQRCode qrValue={isDevLink} isLoading={loadData} />
|
||||
)}
|
||||
</NewWrapper>
|
||||
|
||||
<EventDetailDrawer
|
||||
isVisible={openDrawer}
|
||||
onClose={() => setOpenDrawer(false)}
|
||||
eventId={id as string}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -5,7 +5,6 @@ import { MainColor } from "@/constants/color-palet";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import { apiCheckCodeOtp } from "@/service/api-config";
|
||||
import { GStyles } from "@/styles/global-styles";
|
||||
import { registerForPushNotificationsAsync } from "@/utils/notifications";
|
||||
import AsyncStorage from "@react-native-async-storage/async-storage";
|
||||
import { router, useLocalSearchParams } from "expo-router";
|
||||
import { useEffect, useState } from "react";
|
||||
@@ -17,8 +16,6 @@ import Toast from "react-native-toast-message";
|
||||
export default function VerificationView() {
|
||||
const { nomor } = useLocalSearchParams<{ nomor: string }>();
|
||||
|
||||
console.log("[NOMOR]", nomor);
|
||||
|
||||
const [inputOtp, setInputOtp] = useState<string>("");
|
||||
const [userNumber, setUserNumber] = useState<string>("");
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
|
||||
@@ -1,45 +1,15 @@
|
||||
import { ClickableCustom, TextCustom } from "@/components";
|
||||
import Spacing from "@/components/_ShareComponent/Spacing";
|
||||
import React, { useCallback, useState } from "react";
|
||||
import { router } from "expo-router";
|
||||
import { View } from "react-native";
|
||||
import Icon from "react-native-vector-icons/FontAwesome";
|
||||
import { stylesHome } from "./homeViewStyle";
|
||||
import { router, useFocusEffect } from "expo-router";
|
||||
import { apiJobGetAll } from "@/service/api-client/api-job";
|
||||
import CustomSkeleton from "@/components/_ShareComponent/SkeletonCustom";
|
||||
|
||||
export default function Home_BottomFeatureSection() {
|
||||
const [listData, setListData] = useState<any[] | null>(null);
|
||||
|
||||
const onLoadData = async () => {
|
||||
try {
|
||||
const response = await apiJobGetAll({
|
||||
category: "beranda",
|
||||
});
|
||||
|
||||
console.log("[DATA JOB]", JSON.stringify(response.data, null, 2));
|
||||
const result = response.data
|
||||
.sort(
|
||||
(a: any, b: any) =>
|
||||
new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()
|
||||
)
|
||||
.slice(0, 2);
|
||||
setListData(result);
|
||||
} catch (error) {
|
||||
console.log("[ERROR]", error);
|
||||
}
|
||||
};
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadData();
|
||||
}, [])
|
||||
);
|
||||
|
||||
if (listData === null) {
|
||||
return <CustomSkeleton height={200}/>
|
||||
}
|
||||
|
||||
export default function Home_BottomFeatureSection({
|
||||
listData,
|
||||
}: {
|
||||
listData: any[] | null;
|
||||
}) {
|
||||
return (
|
||||
<>
|
||||
<ClickableCustom onPress={() => router.push("/job")}>
|
||||
|
||||
@@ -139,8 +139,8 @@ export default function UserSearchMainView_V2() {
|
||||
searchQuery: search,
|
||||
emptyMessage: "Tidak ada pengguna ditemukan",
|
||||
emptySearchMessage: "Tidak ada hasil pencarian",
|
||||
skeletonCount: 5,
|
||||
skeletonHeight: 150,
|
||||
skeletonCount: PAGINATION_DEFAULT_TAKE,
|
||||
skeletonHeight: 100,
|
||||
loadingFooterText: "Memuat lebih banyak pengguna...",
|
||||
isInitialLoad,
|
||||
});
|
||||
|
||||
@@ -15,13 +15,14 @@ export async function apiDeviceRegisterToken({
|
||||
data: DeviceTokenData;
|
||||
}) {
|
||||
try {
|
||||
const response = await apiConfig.post(`/mobile/auth/device-tokens`, {
|
||||
data: data,
|
||||
});
|
||||
const response = await apiConfig.post(`/mobile/auth/device-tokens`, data);
|
||||
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
console.error("Failed to register device token:", error);
|
||||
console.error("Response data:", error?.response?.data);
|
||||
console.error("Response status:", error?.response?.status);
|
||||
console.error("Request payload:", data);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user