Compare commits

...

1 Commits

Author SHA1 Message Date
9a915c55d2 Portofolio
Fix:
- Sub bidang bisnis

### No Issu
2025-09-02 18:29:28 +08:00
9 changed files with 201 additions and 76 deletions

View File

@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable react-hooks/exhaustive-deps */
import { StackCustom, ViewWrapper } from "@/components";
import { MainColor } from "@/constants/color-palet";
@@ -8,31 +9,40 @@ import TabSection from "@/screens/Home/tabSection";
import { tabsHome } from "@/screens/Home/tabsList";
import Home_FeatureSection from "@/screens/Home/topFeatureSection";
import { apiUser } from "@/service/api-client/api-user";
import { apiVersion } from "@/service/api-config";
import { Ionicons } from "@expo/vector-icons";
import { Redirect, router, Stack } from "expo-router";
import { useEffect, useState } from "react";
export default function Application() {
const { user } = useAuth();
const [data, setData] = useState<any>({});
const { token, user } = useAuth();
const [data, setData] = useState<any>();
useEffect(() => {
onLoadData();
checkVersion();
}, []);
async function onLoadData() {
const response = await apiUser(user?.id as string);
console.log("User >>", JSON.stringify(response.data.username, null, 2));
console.log("Profile Check >>", JSON.stringify(response.data.Profile.id, null, 2));
console.log("Response profile >>", JSON.stringify(response?.data?.Profile, null, 2));
setData(response.data);
}
const checkVersion = async () => {
const response = await apiVersion();
console.log("Version >>", JSON.stringify(response.data, null, 2));
};
if (data && data?.active === false) {
console.log("User is not active");
return <Redirect href={`/waiting-room`} />;
}
if (data && data?.Profile === null) {
console.log("Profile is null");
return <Redirect href={`/profile/create`} />;
}
@@ -40,7 +50,7 @@ export default function Application() {
<>
<Stack.Screen
options={{
title: "HIPMI",
title: `HIPMI`,
headerLeft: () => (
<Ionicons
name="search"

View File

@@ -1,9 +1,11 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import {
ActionIcon,
AvatarComp,
BaseBox,
ButtonCenteredOnly,
CenterCustom,
Grid,
InformationBox,
SelectCustom,
Spacing,
@@ -13,7 +15,9 @@ import {
TextInputCustom,
ViewWrapper,
} from "@/components";
import { IconPlus } from "@/components/_Icon";
import { MainColor } from "@/constants/color-palet";
import { ICON_SIZE_XLARGE } from "@/constants/constans-value";
import DUMMY_IMAGE from "@/constants/dummy-image-value";
import Portofolio_ButtonCreate from "@/screens/Portofolio/ButtonCreatePortofolio";
import {
@@ -25,10 +29,12 @@ import {
IMasterSubBidangBisnis,
} from "@/types/Type-Master";
import pickImage from "@/utils/pickImage";
import { Ionicons } from "@expo/vector-icons";
import { Image } from "expo-image";
import { useLocalSearchParams } from "expo-router";
import _ from "lodash";
import { useEffect, useState } from "react";
import { Text, View } from "react-native";
import { Text, TouchableOpacity, View } from "react-native";
import PhoneInput, { ICountry } from "react-native-international-phone-number";
import { Avatar } from "react-native-paper";
@@ -46,12 +52,11 @@ export default function PortofolioCreate() {
const [imageUri, setImageUri] = useState<string | null>(null);
const [bidangBisnis, setBidangBisnis] = useState<IMasterBidangBisnis[]>([]);
const [selectBidangId, setSelectBidangId] = useState<string>("");
const [subBidangBisnis, setSubBidangBisnis] = useState<
IMasterSubBidangBisnis[]
>([]);
// const [subBidangSelected, setSubBidangSelected] = useState<string[]>([]);
const [selectedSubBidang, setSelectedSubBidang] = useState<string[]>([]);
const [listSubBidangSelected, setListSubBidangSelected] = useState([
{
id: "",
@@ -82,6 +87,7 @@ export default function PortofolioCreate() {
useEffect(() => {
onLoadMaster();
onLoadMasterSubBidangBisnis();
}, []);
const onLoadMaster = async () => {
@@ -94,15 +100,23 @@ export default function PortofolioCreate() {
}
};
const onLoadMasterSubBidangBisnis = async ({ id }: { id: string }) => {
const onLoadMasterSubBidangBisnis = async () => {
try {
const response = await apiMasterSubBidangBisnis({ id: id });
const response = await apiMasterSubBidangBisnis({});
setSubBidangBisnis(response.data);
} catch (error) {
setSubBidangBisnis([]);
console.log("Error onLoadMasterBidangBisnis", error);
}
};
const handlerSelectedSubBidang = ({ id }: { id: string }) => {
const selectedList = subBidangBisnis?.filter(
(item) => (item?.masterBidangBisnisId as any) === id
);
setSelectedSubBidang(selectedList as any[]);
};
return (
<ViewWrapper
footerComponent={
@@ -136,45 +150,100 @@ export default function PortofolioCreate() {
}))}
value={data.masterBidangBisnisId}
onChange={(value) => {
const isSameBidang = data.masterBidangBisnisId === value;
if (!isSameBidang) {
setListSubBidangSelected([{ id: "" }]);
}
setData({ ...(data as any), masterBidangBisnisId: value });
setSelectBidangId(id as string);
onLoadMasterSubBidangBisnis({ id: value as string });
handlerSelectedSubBidang({ id: value as string });
}}
/>
{/* {listSubBidangSelected.map((item, index) => (
<Grid key={index}>
<Grid.Col span={10}>
<SelectCustom
disabled={selectBidangId === ""}
label="Sub Bidang Usaha"
required
data={subBidangBisnis.map((item) => ({
label: item.name,
value: item.id,
}))}
value={data.sub_bidang_usaha}
onChange={(value) => {
setData({ ...(data as any), sub_bidang_usaha: value });
setListSubBidangSelected([
...listSubBidangSelected,
{ id: value as string },
]);
}}
/>
</Grid.Col>
<Grid.Col
span={2}
style={{ alignItems: "center", justifyContent: "center" }}
>
<TouchableOpacity onPress={() => console.log("delete")}>
<Ionicons name="trash" size={24} color={MainColor.red} />
</TouchableOpacity>
</Grid.Col>
</Grid>
{listSubBidangSelected.map((item, index) => (
<SelectCustom
key={index}
disabled={data.masterBidangBisnisId === ""}
label="Sub Bidang Usaha"
required
data={_.map(selectedSubBidang as any)
.filter((option: any) => {
const selectedValues = listSubBidangSelected.map((s) => s.id);
return (
option.id === item.id || // biarkan tetap muncul kalau ini valuenya sendiri
!selectedValues.includes(option.id)
);
})
.map((e: any) => ({
value: e.id,
label: e.name,
}))}
value={item.id || null}
onChange={(value) => {
const list = _.clone(listSubBidangSelected);
list[index].id = value as any;
setListSubBidangSelected(list);
}}
/>
))}
<ButtonCenteredOnly
<CenterCustom>
<View style={{ flexDirection: "row", alignItems: "center", gap: 10 }}>
<ActionIcon
disabled={
selectedSubBidang.length === listSubBidangSelected.length
}
onPress={() => {
setListSubBidangSelected([
...listSubBidangSelected,
{ id: "" },
]);
}}
icon={
<Ionicons
name="add-circle-outline"
size={ICON_SIZE_XLARGE}
color={MainColor.black}
/>
}
size="xl"
/>
<ActionIcon
disabled={listSubBidangSelected.length <= 1}
onPress={() => {
const list = _.clone(listSubBidangSelected);
list.pop();
setListSubBidangSelected(list);
}}
icon={
<Ionicons
name="remove-circle-outline"
size={ICON_SIZE_XLARGE}
color={MainColor.black}
/>
}
size="xl"
/>
</View>
</CenterCustom>
<Spacing />
{/* <SelectCustom
label="Bidang Usaha"
required
data={bidangBisnis.map((item) => ({
label: item.name,
value: item.id,
}))}
value={null}
onChange={(value) => {
setData({ ...(data as any), masterBidangBisnisId: value });
handlerSelectedSubBidang({ id: value as string });
}}
/> */}
{/* <ButtonCenteredOnly
onPress={() => {
setListSubBidangSelected([...listSubBidangSelected, { id: "" }]);
}}

View File

@@ -40,14 +40,14 @@ export default function Portofolio() {
const response = await apiGetOnePortofolio({ id: id });
console.log(
"Response portofolio >>",
JSON.stringify(response.data.namaBisnis, null, 2)
JSON.stringify(response.data, null, 2)
);
setData(response.data);
}
const userId = user?.id;
const userLoginId = data?.Profile?.User?.id;
const userLoginId = data?.Profile?.userId
console.log("User ID >>", userId);
console.log("User Login ID >>", userLoginId);
@@ -75,7 +75,7 @@ export default function Portofolio() {
<ViewWrapper>
{/* <PorfofolioSection setShowDeleteAlert={setDeleteAlert} data={data} /> */}
<StackCustom>
<Portofolio_Data data={data} />
<Portofolio_Data data={data} listSubBidang={data?.Portofolio_BidangDanSubBidangBisnis as any []} />
<Portofolio_BusinessLocation />
<Portofolio_SocialMediaSection data={data?.Portofolio_MediaSosial} />
<Portofolio_ButtonDelete

View File

@@ -9,11 +9,13 @@ export default function ActionIcon({
onPress,
icon,
size = "md",
disabled = false,
}: {
href?: Href;
onPress?: () => void;
icon: React.ReactNode;
size?: SizeType;
disabled?: boolean;
}) {
const sizeMap = {
xs: 22,
@@ -25,7 +27,7 @@ export default function ActionIcon({
const getSize = (size: SizeType): DimensionValue => {
if (!size) return sizeMap.md; // Default to 'md' if size is undefined
if (typeof size === 'string' && size in sizeMap) {
if (typeof size === "string" && size in sizeMap) {
return sizeMap[size as keyof typeof sizeMap];
}
return size as DimensionValue;
@@ -35,9 +37,10 @@ export default function ActionIcon({
return (
<TouchableOpacity
disabled={disabled}
activeOpacity={0.7}
style={{
backgroundColor: MainColor.yellow,
backgroundColor: disabled ? MainColor.disabled : MainColor.yellow,
padding: 5,
borderRadius: 50,
alignItems: "center",
@@ -46,6 +49,7 @@ export default function ActionIcon({
height: iconSize,
}}
onPress={() => {
if (disabled) return;
if (href) {
router.push(href);
} else {

View File

@@ -14,7 +14,6 @@ import Toast from "react-native-toast-message";
export default function RegisterView() {
const { nomor } = useLocalSearchParams();
const [username, setUsername] = useState("");
// const [loading, setLoading] = useState(false);
const { registerUser, isLoading } = useAuth();
@@ -22,16 +21,22 @@ export default function RegisterView() {
if (!nomor) {
Toast.show({
type: "error",
text1: "Gagal",
text2: "Nomor tidak ditemukan",
text1: "Lengkapi nomor",
});
return false;
}
if (!username) {
Toast.show({
type: "error",
text1: "Gagal",
text2: "Username tidak boleh kosong",
text1: "Username tidak boleh kosong",
});
return false;
}
if (username.includes(" ")) {
Toast.show({
type: "info",
text1: "Username tidak boleh mengandung spasi",
});
return false;
}
@@ -42,9 +47,20 @@ export default function RegisterView() {
const isValid = validasiData();
if (!isValid) return;
if (username.length < 5) {
Toast.show({
type: "info",
text1: "Info",
text2: "Username minimal 5 karakter",
});
return;
}
const usernameLower = username.toLowerCase();
await registerUser({
nomor: nomor as string,
username: username,
username: usernameLower,
});
}
@@ -73,6 +89,11 @@ export default function RegisterView() {
placeholder="Masukkan username"
value={username}
onChangeText={(text) => setUsername(text)}
error={
username.includes(" ")
? "Username tidak boleh mengandung spasi"
: ""
}
/>
<ButtonCustom isLoading={isLoading} onPress={handleRegister}>

View File

@@ -45,7 +45,9 @@ export default function Portofolio_ButtonCreate({
!data.masterBidangBisnisId ||
!data.alamatKantor ||
!data.tlpn ||
!data.deskripsi
!data.deskripsi ||
subBidangSelected.map((item) => item.id).includes("") ||
subBidangSelected.map((item) => item.id).includes(null)
) {
return false;
}
@@ -53,6 +55,10 @@ export default function Portofolio_ButtonCreate({
};
const handleCreatePortofolio = async () => {
console.log(
"Data sub bidang >>",
JSON.stringify(subBidangSelected, null, 2)
);
if (!validaasiData()) {
Toast.show({
type: "info",
@@ -90,18 +96,18 @@ export default function Portofolio_ButtonCreate({
youtube: dataMedsos.youtube,
subBidang: subBidangSelected,
};
try {
const response = await apiPortofolioCreate({
data: newData,
});
console.log("Response >>", JSON.stringify(response, null, 2));
// return router.replace(`/maps/create`);
// return router.push(`/maps/create`);
return router.back();
} catch (error) {
throw error;
}
const response = await apiPortofolioCreate({
data: newData,
});
console.log("Response >>", JSON.stringify(response, null, 2));
// return router.replace(`/maps/create`);
// return router.push(`/maps/create`);
Toast.show({
type: "success",
text1: "Sukses",
text2: "Data berhasil disimpan",
});
return router.back();
} catch (error) {
Toast.show({
type: "error",

View File

@@ -17,7 +17,13 @@ import { FontAwesome, Ionicons } from "@expo/vector-icons";
import { router, useLocalSearchParams } from "expo-router";
import { View } from "react-native";
export default function Portofolio_Data({ data }: { data: any }) {
export default function Portofolio_Data({
data,
listSubBidang,
}: {
data: any;
listSubBidang: any[];
}) {
const { id } = useLocalSearchParams();
const listData = [
@@ -83,6 +89,8 @@ export default function Portofolio_Data({ data }: { data: any }) {
// },
// ];
console.log("List Sub Bidang >>", JSON.stringify(listSubBidang, null, 2));
return (
<>
<BaseBox>
@@ -137,20 +145,24 @@ export default function Portofolio_Data({ data }: { data: any }) {
</Grid.Col>
</Grid>
))}
{/* <View style={{ paddingLeft: 10 }}>
{listSubBidang.map((item, index) => (
<View style={{ paddingLeft: 10 }}>
{listSubBidang?.map((item, index) => (
<Grid key={index}>
<Grid.Col span={2} style={{ alignItems: "center" }}>
{item.icon}
<Ionicons
name="chevron-forward-outline"
size={ICON_SIZE_SMALL}
color="white"
/>
</Grid.Col>
<Grid.Col span={10}>
<TextCustom style={{ paddingLeft: 5 }}>
{item.label}
{item?.MasterSubBidangBisnis?.name || "-"}
</TextCustom>
</Grid.Col>
</Grid>
))}
</View> */}
</View>
</View>
<DividerCustom labelPosition="top" color={AccentColor.blue} />

View File

@@ -9,12 +9,14 @@ export async function apiMasterBidangBisnis() {
}
}
export async function apiMasterSubBidangBisnis({id}: {id: string}) {
export async function apiMasterSubBidangBisnis({ id }: { id?: string }) {
try {
const response = await apiConfig.get(`/master/sub-bidang-bisnis/${id}`);
const selectBidangId = id ? `/${id}` : "";
const response = await apiConfig.get(
`/master/sub-bidang-bisnis${selectBidangId}`
);
return response.data;
} catch (error) {
throw error;
}
}

View File

@@ -14,4 +14,5 @@ export interface IMasterSubBidangBisnis {
isActive: boolean;
createdAt: string;
updatedAt: string;
masterBidangBisnisId: string;
}