Note:
- Fitur notifikasi ke admin dari user baru - Notifikasi ke user bahwa akunnya telah terverifikasi Fix: - app/(application)/(user)/notifications/index.tsx - app/(application)/(user)/waiting-room.tsx - app/(application)/admin/super-admin/[id]/index.tsx - app/(application)/admin/user-access/[id]/index.tsx - context/AuthContext.tsx - screens/Home/tabsList.ts - service/api-admin/api-admin-user-access.ts - service/api-device-token.ts - service/api-notifications.ts - types/type-notification-category.ts Add: - lib/routeApp.ts ### No Issue
This commit is contained in:
@@ -3,9 +3,10 @@ import {
|
||||
NewWrapper,
|
||||
ScrollableCustom,
|
||||
StackCustom,
|
||||
TextCustom
|
||||
TextCustom,
|
||||
} from "@/components";
|
||||
import ListSkeletonComponent from "@/components/_ShareComponent/ListSkeletonComponent";
|
||||
import NoDataText from "@/components/_ShareComponent/NoDataText";
|
||||
import { AccentColor } from "@/constants/color-palet";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import { useNotificationStore } from "@/hooks/use-notification-store";
|
||||
@@ -13,11 +14,14 @@ import { apiGetNotificationsById } from "@/service/api-notifications";
|
||||
import { listOfcategoriesAppNotification } from "@/types/type-notification-category";
|
||||
import { formatChatTime } from "@/utils/formatChatTime";
|
||||
import { router, useFocusEffect } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import { useCallback, useState } from "react";
|
||||
import { RefreshControl, View } from "react-native";
|
||||
|
||||
const selectedCategory = (value: string) => {
|
||||
const category = listOfcategoriesAppNotification.find((c) => c.value === value);
|
||||
const category = listOfcategoriesAppNotification.find(
|
||||
(c) => c.value === value
|
||||
);
|
||||
return category?.label;
|
||||
};
|
||||
|
||||
@@ -83,7 +87,8 @@ export default function Notifications() {
|
||||
id: user?.id as any,
|
||||
category: activeCategory as any,
|
||||
});
|
||||
// console.log("Response Notification", JSON.stringify(response, null, 2));
|
||||
|
||||
console.log("Response Notification", JSON.stringify(response, null, 2));
|
||||
if (response.success) {
|
||||
setListData(response.data);
|
||||
} else {
|
||||
@@ -120,7 +125,9 @@ export default function Notifications() {
|
||||
}
|
||||
>
|
||||
{loading ? (
|
||||
<ListSkeletonComponent/>
|
||||
<ListSkeletonComponent />
|
||||
) : _.isEmpty(listData) ? (
|
||||
<NoDataText text="Belum ada notifikasi" />
|
||||
) : (
|
||||
listData.map((e, i) => (
|
||||
<View key={i}>
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import {
|
||||
AlertDefaultSystem,
|
||||
BoxButtonOnFooter,
|
||||
ButtonCenteredOnly,
|
||||
ButtonCustom,
|
||||
InformationBox,
|
||||
NewWrapper,
|
||||
StackCustom,
|
||||
ViewWrapper,
|
||||
StackCustom
|
||||
} from "@/components";
|
||||
import { ICON_SIZE_BUTTON } from "@/constants/constans-value";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
|
||||
@@ -48,6 +48,7 @@ export default function SuperAdminDetail() {
|
||||
const response = await apiAdminUserAccessUpdateStatus({
|
||||
id: id as string,
|
||||
role: data?.masterUserRoleId === "2" ? "user" : "admin",
|
||||
category: "role"
|
||||
});
|
||||
|
||||
if (!response.success) {
|
||||
|
||||
@@ -9,15 +9,21 @@ import {
|
||||
} from "@/components";
|
||||
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
|
||||
import GridTwoView from "@/components/_ShareComponent/GridTwoView";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import { routeUser } from "@/lib/routeApp";
|
||||
import {
|
||||
apiAdminUserAccessGetById,
|
||||
apiAdminUserAccessUpdateStatus,
|
||||
} from "@/service/api-admin/api-admin-user-access";
|
||||
import {
|
||||
apiNotificationsSendById
|
||||
} from "@/service/api-notifications";
|
||||
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import { useCallback, useState } from "react";
|
||||
import Toast from "react-native-toast-message";
|
||||
|
||||
export default function AdminUserAccessDetail() {
|
||||
const { user } = useAuth();
|
||||
const { id } = useLocalSearchParams();
|
||||
const [data, setData] = useState<any | null>(null);
|
||||
const [loadData, setLoadData] = useState(false);
|
||||
@@ -33,6 +39,7 @@ export default function AdminUserAccessDetail() {
|
||||
try {
|
||||
setLoadData(true);
|
||||
const response = await apiAdminUserAccessGetById({ id: id as string });
|
||||
console.log("[DATA]", JSON.stringify(response.data, null, 2));
|
||||
|
||||
setData(response.data);
|
||||
} catch (error) {
|
||||
@@ -48,6 +55,7 @@ export default function AdminUserAccessDetail() {
|
||||
const response = await apiAdminUserAccessUpdateStatus({
|
||||
id: id as string,
|
||||
active: !data?.active,
|
||||
category: "access",
|
||||
});
|
||||
|
||||
if (!response.success) {
|
||||
@@ -61,6 +69,21 @@ export default function AdminUserAccessDetail() {
|
||||
type: "success",
|
||||
text1: "Update aktifasi berhasil ",
|
||||
});
|
||||
|
||||
if (data.active === false) {
|
||||
await apiNotificationsSendById({
|
||||
data: {
|
||||
title: "Akun anda telah diaktifkan",
|
||||
body: "Selamat menjelajahi HIConnect",
|
||||
userLoginId: user?.id || "",
|
||||
kategoriApp: "OTHER",
|
||||
type: "announcement",
|
||||
deepLink: routeUser.home,
|
||||
},
|
||||
id: id as string,
|
||||
});
|
||||
}
|
||||
|
||||
router.back();
|
||||
} catch (error) {
|
||||
console.log("[ERROR UPDATE STATUS]", error);
|
||||
|
||||
@@ -7,10 +7,10 @@ import {
|
||||
import { apiDeviceTokenDeleted } from "@/service/api-device-token";
|
||||
import { IUser } from "@/types/User";
|
||||
import AsyncStorage from "@react-native-async-storage/async-storage";
|
||||
import * as Device from "expo-device";
|
||||
import { router } from "expo-router";
|
||||
import { createContext, useEffect, useState } from "react";
|
||||
import Toast from "react-native-toast-message";
|
||||
import * as Device from "expo-device";
|
||||
|
||||
// --- Types ---
|
||||
type AuthContextType = {
|
||||
@@ -105,18 +105,6 @@ export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
|
||||
}
|
||||
};
|
||||
|
||||
// const loginWithNomor = async (nomor: string) => {
|
||||
// setIsLoading(true);
|
||||
// try {
|
||||
// const response = await apiLogin({ nomor: nomor });
|
||||
// await AsyncStorage.setItem("kode_otp", response.kodeId);
|
||||
// } catch (error: any) {
|
||||
// throw new Error(error.response?.data?.message || "Gagal kirim OTP");
|
||||
// } finally {
|
||||
// setIsLoading(false);
|
||||
// }
|
||||
// };
|
||||
|
||||
// --- 2. Validasi OTP & cek user ---
|
||||
const validateOtp = async (nomor: string) => {
|
||||
try {
|
||||
@@ -209,7 +197,6 @@ export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const response = await apiRegister({ data: userData });
|
||||
console.log("[REGISTER FETCH]", JSON.stringify(response, null, 2));
|
||||
|
||||
if (!response.success) {
|
||||
Toast.show({
|
||||
@@ -239,42 +226,7 @@ export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
// const registerUser = async (userData: {
|
||||
// username: string;
|
||||
// nomor: string;
|
||||
// termsOfServiceAccepted: boolean;
|
||||
// }) => {
|
||||
// setIsLoading(true);
|
||||
// try {
|
||||
// const response = await apiRegister({ data: userData });
|
||||
// console.log("response", response);
|
||||
|
||||
// const { token } = response;
|
||||
// if (!response.success) {
|
||||
// Toast.show({
|
||||
// type: "info",
|
||||
// text1: "Info",
|
||||
// text2: response.message,
|
||||
// });
|
||||
|
||||
// return;
|
||||
// }
|
||||
|
||||
// setToken(token);
|
||||
// await AsyncStorage.setItem("authToken", token);
|
||||
// Toast.show({
|
||||
// type: "success",
|
||||
// text1: "Sukses",
|
||||
// text2: "Anda berhasil terdaftar",
|
||||
// });
|
||||
// router.replace("/(application)/(user)/waiting-room");
|
||||
// return;
|
||||
// } catch (error: any) {
|
||||
// console.log("Error register", error);
|
||||
// } finally {
|
||||
// setIsLoading(false);
|
||||
// }
|
||||
// };
|
||||
|
||||
// --- 5. Logout ---
|
||||
|
||||
@@ -284,7 +236,8 @@ export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
|
||||
setToken(null);
|
||||
setUser(null);
|
||||
|
||||
const deviceId = Device.osInternalBuildId || Device.modelName || "unknown";
|
||||
const deviceId =
|
||||
Device.osInternalBuildId || Device.modelName || "unknown";
|
||||
|
||||
await AsyncStorage.removeItem("authToken");
|
||||
await AsyncStorage.removeItem("userData");
|
||||
|
||||
9
lib/routeApp.ts
Normal file
9
lib/routeApp.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
export { routeAdmin, routeUser };
|
||||
|
||||
const routeAdmin = {
|
||||
userAccess: ({ id }: { id: string }) => `/admin/user-access/${id}`,
|
||||
};
|
||||
|
||||
const routeUser = {
|
||||
home: `/(user)/home`,
|
||||
};
|
||||
@@ -1,6 +1,13 @@
|
||||
import { ITabs } from "@/components/_Interface/types";
|
||||
import { Platform } from "react-native";
|
||||
|
||||
export const tabsHome: any = ({acceptedForumTermsAt, profileId}: {acceptedForumTermsAt: Date, profileId: string}) => [
|
||||
export const tabsHome: any = ({
|
||||
acceptedForumTermsAt,
|
||||
profileId,
|
||||
}: {
|
||||
acceptedForumTermsAt: Date;
|
||||
profileId: string;
|
||||
}) => [
|
||||
{
|
||||
id: "forum",
|
||||
icon: "chatbubble-ellipses-outline",
|
||||
@@ -25,8 +32,8 @@ export const tabsHome: any = ({acceptedForumTermsAt, profileId}: {acceptedForumT
|
||||
activeIcon: "map",
|
||||
label: "Maps",
|
||||
path: "/maps",
|
||||
isActive: true,
|
||||
disabled: false,
|
||||
isActive: Platform.OS === "ios" ? true : false,
|
||||
disabled: Platform.OS === "ios" ? false : true,
|
||||
},
|
||||
{
|
||||
id: "profile",
|
||||
|
||||
@@ -28,13 +28,15 @@ export const apiAdminUserAccessUpdateStatus = async ({
|
||||
id,
|
||||
active,
|
||||
role,
|
||||
category,
|
||||
}: {
|
||||
id: string;
|
||||
active?: boolean;
|
||||
role?: "user" | "admin" | "super_admin";
|
||||
category: "access" | "role";
|
||||
}) => {
|
||||
try {
|
||||
const response = await apiConfig.put(`/mobile/admin/user/${id}`, {
|
||||
const response = await apiConfig.put(`/mobile/admin/user/${id}?category=${category}`, {
|
||||
data: {
|
||||
active,
|
||||
role,
|
||||
|
||||
@@ -31,7 +31,7 @@ export async function apiDeviceTokenDeleted({ userId, deviceId }: { userId: stri
|
||||
const response = await apiConfig.delete(
|
||||
`/mobile/auth/device-tokens/${userId}?deviceId=${deviceId}`
|
||||
);
|
||||
console.log("Device token deleted:", response.data);
|
||||
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error("Failed to delete device token:", error);
|
||||
@@ -42,7 +42,7 @@ export async function apiDeviceTokenDeleted({ userId, deviceId }: { userId: stri
|
||||
export async function apiGetAllTokenDevice() {
|
||||
try {
|
||||
const response = await apiConfig.get(`/mobile/auth/device-tokens`);
|
||||
console.log("Device token deleted:", response.data);
|
||||
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error("Failed to delete device token:", error);
|
||||
|
||||
@@ -1,17 +1,9 @@
|
||||
import { TypeNotificationCategoryApp, TypeOfTilteCategoryApp } from "@/types/type-notification-category";
|
||||
import {
|
||||
NotificationProp,
|
||||
TypeNotificationCategoryApp
|
||||
} from "@/types/type-notification-category";
|
||||
import { apiConfig } from "./api-config";
|
||||
|
||||
type NotificationProp = {
|
||||
title: TypeOfTilteCategoryApp;
|
||||
body: string;
|
||||
userLoginId: string;
|
||||
appId?: string;
|
||||
status?: string;
|
||||
type?: "announcement" | "trigger";
|
||||
deepLink?: string;
|
||||
kategoriApp?: TypeNotificationCategoryApp
|
||||
};
|
||||
|
||||
export async function apiNotificationsSend({
|
||||
data,
|
||||
}: {
|
||||
@@ -28,12 +20,30 @@ export async function apiNotificationsSend({
|
||||
}
|
||||
}
|
||||
|
||||
export async function apiNotificationsSendById({
|
||||
data,
|
||||
id,
|
||||
}: {
|
||||
data: NotificationProp;
|
||||
id: string;
|
||||
}) {
|
||||
try {
|
||||
const response = await apiConfig.post(`/mobile/notification/${id}`, {
|
||||
data: data,
|
||||
});
|
||||
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function apiGetNotificationsById({
|
||||
id,
|
||||
category,
|
||||
}: {
|
||||
id: string;
|
||||
category: TypeNotificationCategoryApp
|
||||
category: TypeNotificationCategoryApp;
|
||||
}) {
|
||||
console.log("ID", id);
|
||||
console.log("Category", category);
|
||||
@@ -49,7 +59,13 @@ export async function apiGetNotificationsById({
|
||||
}
|
||||
}
|
||||
|
||||
export async function apiNotificationUnreadCount({ id, role }: { id: string, role: "user" | "admin" }) {
|
||||
export async function apiNotificationUnreadCount({
|
||||
id,
|
||||
role,
|
||||
}: {
|
||||
id: string;
|
||||
role: "user" | "admin";
|
||||
}) {
|
||||
try {
|
||||
const response = await apiConfig.get(
|
||||
`/mobile/notification/${id}/unread-count?role=${role}`
|
||||
@@ -62,8 +78,7 @@ export async function apiNotificationUnreadCount({ id, role }: { id: string, rol
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export async function apiNotificationMarkAsRead({id}: {id: string}) {
|
||||
export async function apiNotificationMarkAsRead({ id }: { id: string }) {
|
||||
try {
|
||||
const response = await apiConfig.put(`/mobile/notification/${id}`);
|
||||
return response.data;
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
export type NotificationProp = {
|
||||
title: TypeOfTilteCategoryApp | string
|
||||
body: string;
|
||||
userLoginId?: string;
|
||||
appId?: string;
|
||||
status?: string;
|
||||
type?: "announcement" | "trigger";
|
||||
deepLink?: string;
|
||||
kategoriApp?: TypeNotificationCategoryApp
|
||||
};
|
||||
|
||||
|
||||
|
||||
export type TypeNotificationCategoryApp =
|
||||
| "EVENT"
|
||||
| "JOB"
|
||||
@@ -6,9 +19,9 @@ export type TypeNotificationCategoryApp =
|
||||
| "INVESTASI"
|
||||
| "COLLABORATION"
|
||||
| "FORUM"
|
||||
| "ACCESS";
|
||||
| "OTHER";
|
||||
|
||||
export type TypeOfTilteCategoryApp = "Pendaftaran User Baru" | "Other" | string;
|
||||
export type TypeOfTilteCategoryApp = "Pendaftaran User Baru" | "Other"
|
||||
|
||||
export const listOfcategoriesAppNotification = [
|
||||
{ value: "event", label: "Event" },
|
||||
@@ -18,4 +31,5 @@ export const listOfcategoriesAppNotification = [
|
||||
{ value: "investasi", label: "Investasi" },
|
||||
{ value: "forum", label: "Forum" },
|
||||
{ value: "collaboration", label: "Collaboration" },
|
||||
{ value: "other", label: "Lainnya" },
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user