Integrasi Admin: User Acces & Super Admin

Add:
- admin/super-admin/
- admin/user-access/
- service/api-admin/

Fix:
- (user)/profile/[id]/index: penambahan useData dari useAuthuntuk merestart value masterRole
- integrasi pada tampilan admin

### No Issue
This commit is contained in:
2025-10-14 17:28:40 +08:00
parent f750d158be
commit 5f36620988
16 changed files with 833 additions and 174 deletions

View File

@@ -0,0 +1,124 @@
/* eslint-disable react-hooks/exhaustive-deps */
import {
BoxButtonOnFooter,
ButtonCustom,
LoaderCustom,
StackCustom,
TextCustom,
ViewWrapper,
} from "@/components";
import AdminBackButtonAntTitle from "@/components/_ShareComponent/Admin/BackButtonAntTitle";
import GridTwoView from "@/components/_ShareComponent/GridTwoView";
import {
apiAdminUserAccessGetById,
apiAdminUserAccessUpdateStatus,
} from "@/service/api-admin/api-admin-user-access";
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
import { useCallback, useState } from "react";
import Toast from "react-native-toast-message";
export default function AdminUserAccessDetail() {
const { id } = useLocalSearchParams();
const [data, setData] = useState<any | null>(null);
const [loadData, setLoadData] = useState(false);
const [isLoading, setLoading] = useState(false);
useFocusEffect(
useCallback(() => {
onLoadData();
}, [id])
);
const onLoadData = async () => {
try {
setLoadData(true);
const response = await apiAdminUserAccessGetById({ id: id as string });
setData(response.data);
} catch (error) {
console.log("[ERROR LOAD DATA]", error);
} finally {
setLoadData(false);
}
};
const handlerSubmit = async () => {
try {
setLoading(true);
const response = await apiAdminUserAccessUpdateStatus({
id: id as string,
active: !data?.active,
});
if (!response.success) {
Toast.show({
type: "error",
text1: "Update aktifasi gagal",
});
return;
}
Toast.show({
type: "success",
text1: "Update aktifasi berhasil ",
});
router.back();
} catch (error) {
console.log("[ERROR UPDATE STATUS]", error);
} finally {
setLoading(false);
}
};
return (
<>
<ViewWrapper
headerComponent={<AdminBackButtonAntTitle title={`Detail User`} />}
footerComponent={
data && (
<BoxButtonOnFooter>
<ButtonCustom
isLoading={isLoading}
backgroundColor={data?.active ? "red" : "green"}
textColor={"white"}
onPress={handlerSubmit}
>
{data?.active ? "Hapus Akses" : "Berikan Akses"}
</ButtonCustom>
</BoxButtonOnFooter>
)
}
>
{loadData ? (
<LoaderCustom />
) : (
<StackCustom>
{listData(data && data)?.map((item: any, index: number) => (
<GridTwoView
key={index}
spanLeft={4}
spanRight={8}
leftIcon={<TextCustom bold>{item?.label}</TextCustom>}
rightIcon={<TextCustom>{item?.value}</TextCustom>}
/>
))}
</StackCustom>
)}
</ViewWrapper>
</>
);
}
const listData = (data: any) => [
{
label: "Username",
value: (data && data?.username) || "-",
},
{
label: "Aktivasi",
value: data && data?.active ? "Aktif" : "Tidak Aktif",
},
{
label: "Nomor",
value: (data && `+${data?.nomor}`) || "-",
},
];

View File

@@ -0,0 +1,143 @@
/* eslint-disable react-hooks/exhaustive-deps */
import {
BadgeCustom,
CenterCustom,
Divider,
SearchInput,
StackCustom,
TextCustom,
ViewWrapper,
} from "@/components";
import AdminComp_BoxTitle from "@/components/_ShareComponent/Admin/BoxTitlePage";
import { GridViewCustomSpan } from "@/components/_ShareComponent/GridViewCustomSpan";
import { MainColor } from "@/constants/color-palet";
import { ICON_SIZE_XLARGE } from "@/constants/constans-value";
import { apiAdminUserAccessGetAll } from "@/service/api-admin/api-admin-user-access";
import { Ionicons } from "@expo/vector-icons";
import { router, useFocusEffect } from "expo-router";
import _ from "lodash";
import { useCallback, useState } from "react";
export default function AdminUserAccess() {
const [listData, setListData] = useState<any[] | null>(null);
const [search, setSearch] = useState("");
useFocusEffect(
useCallback(() => {
onLoadData();
}, [search])
);
const onLoadData = async () => {
try {
const response = await apiAdminUserAccessGetAll({
search: search,
category: "only-user",
});
if (response.success) {
setListData(response.data);
}
} catch (error) {
console.log("[ERROR LOAD DATA]", error);
}
};
const rightComponent = () => {
return (
<>
<SearchInput
containerStyle={{ width: "100%", marginBottom: 0 }}
placeholder="Cari User"
onChangeText={(text) => setSearch(text)}
/>
</>
);
};
return (
<>
<ViewWrapper
headerComponent={
<AdminComp_BoxTitle
title="User Access"
rightComponent={rightComponent()}
/>
}
>
<GridViewCustomSpan
span1={2}
span2={5}
span3={5}
component1={
<TextCustom align="center" bold>
Aksi
</TextCustom>
}
component2={
<TextCustom align="center" bold>
Username
</TextCustom>
}
component3={
<TextCustom align="center" bold>
Status Akses
</TextCustom>
}
/>
<Divider />
<StackCustom>
{_.isEmpty(listData) ? (
<TextCustom align="center" color="gray" size={"small"}>
Tidak ada data
</TextCustom>
) : (
listData?.map((item: any, index: number) => (
<GridViewCustomSpan
key={index}
span1={2}
span2={5}
span3={5}
component1={
<CenterCustom>
<Ionicons
onPress={() =>
router.push(`/admin/user-access/${item?.id}`)
}
name="open"
size={ICON_SIZE_XLARGE}
color={MainColor.yellow}
/>
</CenterCustom>
// <ButtonCustom
// onPress={() =>
// router.push(`/admin/user-access/${item?.id}`)
// }
// >
// Detail
// </ButtonCustom>
}
component2={
<TextCustom bold truncate>
{item?.username || "-"}
</TextCustom>
}
component3={
<CenterCustom>
{item?.active ? (
<BadgeCustom color="green">Aktif</BadgeCustom>
) : (
<BadgeCustom color="red">Tidak Aktif</BadgeCustom>
)}
</CenterCustom>
}
style3={{ alignItems: "center", justifyContent: "center" }}
/>
))
)}
</StackCustom>
</ViewWrapper>
</>
);
}