Fix code/
User Pages - app/(application)/(user)/home.tsx - app/(application)/(user)/portofolio/[id]/create.tsx Components - components/_ShareComponent/AppHeader.tsx Screens - screens/Portofolio/ScreenPortofolioCreate.tsx Config & Dependencies - app.config.js - package.json - bun.lock iOS - ios/HIPMIBadungConnect.xcodeproj/project.pbxproj - ios/HIPMIBadungConnect/Info.plist Docs - docs/prompt-for-qwen-code.md ### No issue
This commit is contained in:
@@ -34,7 +34,7 @@ export default {
|
||||
associatedDomains: [
|
||||
"applinks:cld-dkr-hipmi-stg.wibudev.com",
|
||||
],
|
||||
buildNumber: "4",
|
||||
buildNumber: "5",
|
||||
},
|
||||
|
||||
android: {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
import { BasicWrapper, StackCustom, ViewWrapper } from "@/components";
|
||||
import AppHeader from "@/components/_ShareComponent/AppHeader";
|
||||
import CustomSkeleton from "@/components/_ShareComponent/SkeletonCustom";
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
@@ -117,28 +118,36 @@ export default function Application() {
|
||||
<>
|
||||
<Stack.Screen
|
||||
options={{
|
||||
title: `HIPMI`,
|
||||
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} />
|
||||
),
|
||||
header: () => (
|
||||
<AppHeader
|
||||
title="HIPMI"
|
||||
showBack={false}
|
||||
left={
|
||||
data ? (
|
||||
<Ionicons
|
||||
name="search"
|
||||
size={20}
|
||||
color={MainColor.yellow}
|
||||
onPress={() => {
|
||||
router.push("/user-search");
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<CustomSkeleton height={30} width={30} radius={100} />
|
||||
)
|
||||
}
|
||||
right={
|
||||
data ? (
|
||||
<HeaderBell />
|
||||
) : (
|
||||
<CustomSkeleton height={30} width={30} radius={100} />
|
||||
)
|
||||
}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
|
||||
<ViewWrapper
|
||||
refreshControl={
|
||||
<RefreshControl
|
||||
|
||||
@@ -1,365 +1,5 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
import {
|
||||
ActionIcon,
|
||||
AvatarComp,
|
||||
BaseBox,
|
||||
ButtonCenteredOnly,
|
||||
CenterCustom,
|
||||
Grid,
|
||||
InformationBox,
|
||||
NewWrapper,
|
||||
SelectCustom,
|
||||
Spacing,
|
||||
StackCustom,
|
||||
TextAreaCustom,
|
||||
TextCustom,
|
||||
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 {
|
||||
apiMasterBidangBisnis,
|
||||
apiMasterSubBidangBisnis,
|
||||
} from "@/service/api-client/api-master";
|
||||
import {
|
||||
IMasterBidangBisnis,
|
||||
IMasterSubBidangBisnis,
|
||||
} from "@/types/Type-Master";
|
||||
import pickImage from "@/utils/pickImage";
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
import { Image } from "expo-image";
|
||||
import { useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { Text, TouchableOpacity, View } from "react-native";
|
||||
import PhoneInput, { ICountry } from "react-native-international-phone-number";
|
||||
import { Avatar } from "react-native-paper";
|
||||
import { Admin_ScreenPortofolioCreate } from "@/screens/Portofolio/ScreenPortofolioCreate";
|
||||
|
||||
export default function PortofolioCreate() {
|
||||
const { id } = useLocalSearchParams();
|
||||
const [selectedCountry, setSelectedCountry] = useState<null | ICountry>(null);
|
||||
const [inputValue, setInputValue] = useState<string>("");
|
||||
const [data, setData] = useState({
|
||||
namaBisnis: "",
|
||||
masterBidangBisnisId: "",
|
||||
alamatKantor: "",
|
||||
tlpn: "",
|
||||
deskripsi: "",
|
||||
});
|
||||
const [imageUri, setImageUri] = useState<string | null>(null);
|
||||
|
||||
const [bidangBisnis, setBidangBisnis] = useState<IMasterBidangBisnis[]>([]);
|
||||
const [subBidangBisnis, setSubBidangBisnis] = useState<
|
||||
IMasterSubBidangBisnis[]
|
||||
>([]);
|
||||
|
||||
const [selectedSubBidang, setSelectedSubBidang] = useState<string[]>([]);
|
||||
const [listSubBidangSelected, setListSubBidangSelected] = useState([
|
||||
{
|
||||
id: "",
|
||||
},
|
||||
]);
|
||||
|
||||
const [dataMedsos, setDataMedsos] = useState({
|
||||
facebook: "",
|
||||
twitter: "",
|
||||
instagram: "",
|
||||
youtube: "",
|
||||
tiktok: "",
|
||||
});
|
||||
|
||||
const [isLoadingCreate, setIsLoadingCreate] = useState(false);
|
||||
|
||||
function handleInputValue(phoneNumber: string) {
|
||||
setInputValue(phoneNumber);
|
||||
const callingCode = selectedCountry?.callingCode.replace(/^\+/, "") || "";
|
||||
let fixNumber = inputValue.replace(/\s+/g, "").replace(/^0+/, "");
|
||||
const realNumber = callingCode + fixNumber;
|
||||
setData({ ...data, tlpn: realNumber });
|
||||
}
|
||||
|
||||
function handleSelectedCountry(country: ICountry) {
|
||||
setSelectedCountry(country);
|
||||
}
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadMaster();
|
||||
onLoadMasterSubBidangBisnis();
|
||||
}, [])
|
||||
);
|
||||
|
||||
const onLoadMaster = async () => {
|
||||
try {
|
||||
const response = await apiMasterBidangBisnis();
|
||||
setBidangBisnis(response.data);
|
||||
} catch (error) {
|
||||
setBidangBisnis([]);
|
||||
console.log("Error onLoadMasterBidangBisnis", error);
|
||||
}
|
||||
};
|
||||
|
||||
const onLoadMasterSubBidangBisnis = async () => {
|
||||
try {
|
||||
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 (
|
||||
<NewWrapper
|
||||
footerComponent={
|
||||
<Portofolio_ButtonCreate
|
||||
id={id as string}
|
||||
data={data}
|
||||
dataMedsos={dataMedsos}
|
||||
imageUri={imageUri}
|
||||
subBidangSelected={listSubBidangSelected}
|
||||
isLoadingCreate={isLoadingCreate}
|
||||
setIsLoadingCreate={setIsLoadingCreate}
|
||||
/>
|
||||
}
|
||||
>
|
||||
{/* <TextCustom>Portofolio Create {id}</TextCustom> */}
|
||||
<StackCustom gap={"xs"}>
|
||||
<InformationBox text="Lengkapi data bisnis anda." />
|
||||
<TextInputCustom
|
||||
required
|
||||
label="Nama Bisnis"
|
||||
placeholder="Masukkan nama bisnis"
|
||||
onChangeText={(value: any) => setData({ ...data, namaBisnis: value })}
|
||||
/>
|
||||
|
||||
<SelectCustom
|
||||
label="Bidang Usaha"
|
||||
required
|
||||
data={bidangBisnis.map((item) => ({
|
||||
label: item.name,
|
||||
value: item.id,
|
||||
}))}
|
||||
value={data.masterBidangBisnisId}
|
||||
onChange={(value) => {
|
||||
const isSameBidang = data.masterBidangBisnisId === value;
|
||||
|
||||
if (!isSameBidang) {
|
||||
setListSubBidangSelected([{ id: "" }]);
|
||||
}
|
||||
|
||||
setData({ ...(data as any), masterBidangBisnisId: value });
|
||||
handlerSelectedSubBidang({ id: value as string });
|
||||
}}
|
||||
/>
|
||||
|
||||
{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);
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
|
||||
<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: "" }]);
|
||||
}}
|
||||
>
|
||||
Tambah Pilihan
|
||||
</ButtonCenteredOnly>
|
||||
<Spacing /> */}
|
||||
|
||||
{/* <TextCustom>{JSON.stringify(bidangBisnis, null, 2)}</TextCustom> */}
|
||||
|
||||
<View>
|
||||
<View style={{ flexDirection: "row", alignItems: "center" }}>
|
||||
<TextCustom semiBold style={{ color: MainColor.white_gray }}>
|
||||
Nomor Telepon
|
||||
</TextCustom>
|
||||
<Text style={{ color: "red" }}> *</Text>
|
||||
</View>
|
||||
<Spacing height={5} />
|
||||
<PhoneInput
|
||||
value={inputValue}
|
||||
onChangePhoneNumber={handleInputValue}
|
||||
selectedCountry={selectedCountry}
|
||||
onChangeSelectedCountry={handleSelectedCountry}
|
||||
defaultCountry="ID"
|
||||
placeholder="xxx-xxx-xxx"
|
||||
/>
|
||||
</View>
|
||||
<Spacing />
|
||||
|
||||
<TextInputCustom
|
||||
required
|
||||
label="Alamat Bisnis"
|
||||
placeholder="Masukkan alamat bisnis"
|
||||
onChangeText={(value: any) =>
|
||||
setData({ ...data, alamatKantor: value })
|
||||
}
|
||||
/>
|
||||
|
||||
<TextAreaCustom
|
||||
label="Deskripsi Bisnis"
|
||||
placeholder="Masukkan deskripsi bisnis"
|
||||
value={data.deskripsi}
|
||||
onChangeText={(value: any) => setData({ ...data, deskripsi: value })}
|
||||
autosize
|
||||
minRows={2}
|
||||
maxRows={5}
|
||||
required
|
||||
showCount
|
||||
maxLength={1000}
|
||||
/>
|
||||
<Spacing />
|
||||
|
||||
{/* Logo */}
|
||||
<InformationBox text="Upload logo bisnis anda untuk di tampilaka pada portofolio." />
|
||||
|
||||
<CenterCustom>
|
||||
<Avatar.Image
|
||||
source={imageUri ? { uri: imageUri } : DUMMY_IMAGE.dummy_image}
|
||||
size={200}
|
||||
/>
|
||||
</CenterCustom>
|
||||
<Spacing />
|
||||
<ButtonCenteredOnly
|
||||
icon="upload"
|
||||
onPress={() => {
|
||||
pickImage({
|
||||
setImageUri,
|
||||
});
|
||||
}}
|
||||
>
|
||||
Upload
|
||||
</ButtonCenteredOnly>
|
||||
<Spacing height={40} />
|
||||
|
||||
{/* Social Media */}
|
||||
<InformationBox text="Isi hanya pada sosial media yang anda miliki." />
|
||||
<TextInputCustom
|
||||
label="Tiktok"
|
||||
placeholder="Masukkan username tiktok"
|
||||
onChangeText={(value: any) =>
|
||||
setDataMedsos({ ...dataMedsos, tiktok: value })
|
||||
}
|
||||
/>
|
||||
<TextInputCustom
|
||||
label="Facebook"
|
||||
placeholder="Masukkan username facebook"
|
||||
onChangeText={(value: any) =>
|
||||
setDataMedsos({ ...dataMedsos, facebook: value })
|
||||
}
|
||||
/>
|
||||
<TextInputCustom
|
||||
label="Instagram"
|
||||
placeholder="Masukkan username instagram"
|
||||
onChangeText={(value: any) =>
|
||||
setDataMedsos({ ...dataMedsos, instagram: value })
|
||||
}
|
||||
/>
|
||||
<TextInputCustom
|
||||
label="Twitter"
|
||||
placeholder="Masukkan username twitter"
|
||||
onChangeText={(value: any) =>
|
||||
setDataMedsos({ ...dataMedsos, twitter: value })
|
||||
}
|
||||
/>
|
||||
<TextInputCustom
|
||||
label="Youtube"
|
||||
placeholder="Masukkan username youtube"
|
||||
onChangeText={(value: any) =>
|
||||
setDataMedsos({ ...dataMedsos, youtube: value })
|
||||
}
|
||||
/>
|
||||
{/* <Spacing /> */}
|
||||
</StackCustom>
|
||||
</NewWrapper>
|
||||
);
|
||||
return <Admin_ScreenPortofolioCreate />;
|
||||
}
|
||||
|
||||
113
components/_ShareComponent/AppHeader.tsx
Normal file
113
components/_ShareComponent/AppHeader.tsx
Normal file
@@ -0,0 +1,113 @@
|
||||
import { MainColor } from "@/constants/color-palet";
|
||||
import { Platform, StyleSheet, Text, View } from "react-native";
|
||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||
import { BackButton } from "..";
|
||||
|
||||
type Props = {
|
||||
title: string;
|
||||
right?: React.ReactNode;
|
||||
showBack?: boolean;
|
||||
onPressLeft?: () => void;
|
||||
left?: React.ReactNode;
|
||||
};
|
||||
|
||||
export default function AppHeader({
|
||||
title,
|
||||
right,
|
||||
showBack = true,
|
||||
onPressLeft,
|
||||
left,
|
||||
}: Props) {
|
||||
const insets = useSafeAreaInsets();
|
||||
|
||||
// iOS 16+ detection (Dynamic Island) - insets.top > 47 indicates Dynamic Island
|
||||
const isIOS26Plus =
|
||||
Platform.OS === "ios" && insets.top > 47;
|
||||
|
||||
// Dynamic padding berdasarkan platform dan iOS version
|
||||
const paddingTop =
|
||||
Platform.OS === "ios"
|
||||
? isIOS26Plus
|
||||
? insets.top - 10
|
||||
: insets.top
|
||||
: 10;
|
||||
|
||||
const paddingBottom = Platform.OS === "ios" ? 8 : 13;
|
||||
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
{
|
||||
backgroundColor: MainColor.darkblue,
|
||||
paddingTop,
|
||||
paddingBottom,
|
||||
},
|
||||
]}
|
||||
>
|
||||
{/* Header Container dengan absolute positioning untuk title center */}
|
||||
<View style={styles.headerApp}>
|
||||
{/* Left Section - Absolute Left */}
|
||||
<View style={styles.headerLeft}>
|
||||
{showBack ? (
|
||||
<BackButton onPress={onPressLeft} />
|
||||
) : left ? (
|
||||
left
|
||||
) : (
|
||||
<View style={styles.placeholder} />
|
||||
)}
|
||||
</View>
|
||||
|
||||
{/* Title - Absolute Center */}
|
||||
<View style={styles.headerCenter}>
|
||||
<Text
|
||||
style={styles.headerTitle}
|
||||
numberOfLines={1}
|
||||
ellipsizeMode="tail"
|
||||
>
|
||||
{title ? title.charAt(0).toUpperCase() + title.slice(1) : ""}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
{/* Right Section - Absolute Right */}
|
||||
<View style={styles.headerRight}>
|
||||
{right}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
headerApp: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
paddingHorizontal: 16,
|
||||
height: 44, // Fixed height untuk consistency
|
||||
},
|
||||
headerLeft: {
|
||||
position: "absolute",
|
||||
left: 16,
|
||||
zIndex: 1,
|
||||
},
|
||||
headerCenter: {
|
||||
flex: 1,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
},
|
||||
headerRight: {
|
||||
position: "absolute",
|
||||
right: 16,
|
||||
zIndex: 1,
|
||||
},
|
||||
placeholder: {
|
||||
width: 40,
|
||||
height: 40,
|
||||
},
|
||||
headerTitle: {
|
||||
color: MainColor.yellow,
|
||||
fontSize: 18,
|
||||
fontWeight: "600",
|
||||
textAlign: "center",
|
||||
},
|
||||
});
|
||||
@@ -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/event/[id]/[status]/index.tsx
|
||||
Folder tujuan: screens/Admin/Event
|
||||
Nama file utama: ScreenEventDetail.tsx
|
||||
Nama function utama: Admin_ScreenEventDetail
|
||||
File source: app/(application)/(user)/portofolio/[id]/create.tsx
|
||||
Folder tujuan: screens/Portofolio
|
||||
Nama file utama: ScreenPortofolioCreate.tsx
|
||||
Nama function utama: Admin_ScreenPortofolioCreate
|
||||
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"
|
||||
|
||||
@@ -189,6 +189,12 @@
|
||||
0D62979D96BF4B99AB9FBE7C /* Remove signature files (Xcode workaround) */,
|
||||
49B80EF12BE8476C86534CEA /* Remove signature files (Xcode workaround) */,
|
||||
6218417B3C954EFF9B5F4853 /* Remove signature files (Xcode workaround) */,
|
||||
7B5AE3770142492D84AEAAB3 /* Remove signature files (Xcode workaround) */,
|
||||
0F1E3753571D42AB932C4F72 /* Remove signature files (Xcode workaround) */,
|
||||
B020BDE42E304FBD99BD2279 /* Remove signature files (Xcode workaround) */,
|
||||
6ECA5F81B0BC4C70A91BE265 /* Remove signature files (Xcode workaround) */,
|
||||
44265583B67C48F2A24BA93E /* Remove signature files (Xcode workaround) */,
|
||||
D5CA1D54CFF74AB4B8B5B583 /* Remove signature files (Xcode workaround) */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -1103,6 +1109,108 @@
|
||||
rm -rf \"$CONFIGURATION_BUILD_DIR/MapLibre.xcframework-ios.signature\";
|
||||
";
|
||||
};
|
||||
7B5AE3770142492D84AEAAB3 /* 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\";
|
||||
";
|
||||
};
|
||||
0F1E3753571D42AB932C4F72 /* 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\";
|
||||
";
|
||||
};
|
||||
B020BDE42E304FBD99BD2279 /* 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\";
|
||||
";
|
||||
};
|
||||
6ECA5F81B0BC4C70A91BE265 /* 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\";
|
||||
";
|
||||
};
|
||||
44265583B67C48F2A24BA93E /* 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\";
|
||||
";
|
||||
};
|
||||
D5CA1D54CFF74AB4B8B5B583 /* 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>4</string>
|
||||
<string>5</string>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
|
||||
340
screens/Portofolio/ScreenPortofolioCreate.tsx
Normal file
340
screens/Portofolio/ScreenPortofolioCreate.tsx
Normal file
@@ -0,0 +1,340 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
import {
|
||||
ActionIcon,
|
||||
ButtonCenteredOnly,
|
||||
CenterCustom,
|
||||
InformationBox,
|
||||
NewWrapper,
|
||||
SelectCustom,
|
||||
Spacing,
|
||||
StackCustom,
|
||||
TextAreaCustom,
|
||||
TextCustom,
|
||||
TextInputCustom,
|
||||
} from "@/components";
|
||||
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 {
|
||||
apiMasterBidangBisnis,
|
||||
apiMasterSubBidangBisnis,
|
||||
} from "@/service/api-client/api-master";
|
||||
import {
|
||||
IMasterBidangBisnis,
|
||||
IMasterSubBidangBisnis,
|
||||
} from "@/types/Type-Master";
|
||||
import pickImage from "@/utils/pickImage";
|
||||
import { Ionicons } from "@expo/vector-icons";
|
||||
import { useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||
import _ from "lodash";
|
||||
import { useCallback, useState } from "react";
|
||||
import { Text, View } from "react-native";
|
||||
import PhoneInput, { ICountry } from "react-native-international-phone-number";
|
||||
import { Avatar } from "react-native-paper";
|
||||
|
||||
export function Admin_ScreenPortofolioCreate() {
|
||||
const { id } = useLocalSearchParams();
|
||||
const [selectedCountry, setSelectedCountry] = useState<null | ICountry>(null);
|
||||
const [inputValue, setInputValue] = useState<string>("");
|
||||
const [data, setData] = useState({
|
||||
namaBisnis: "",
|
||||
masterBidangBisnisId: "",
|
||||
alamatKantor: "",
|
||||
tlpn: "",
|
||||
deskripsi: "",
|
||||
});
|
||||
const [imageUri, setImageUri] = useState<string | null>(null);
|
||||
|
||||
const [bidangBisnis, setBidangBisnis] = useState<IMasterBidangBisnis[]>([]);
|
||||
const [subBidangBisnis, setSubBidangBisnis] = useState<
|
||||
IMasterSubBidangBisnis[]
|
||||
>([]);
|
||||
|
||||
const [selectedSubBidang, setSelectedSubBidang] = useState<string[]>([]);
|
||||
const [listSubBidangSelected, setListSubBidangSelected] = useState([
|
||||
{
|
||||
id: "",
|
||||
},
|
||||
]);
|
||||
|
||||
const [dataMedsos, setDataMedsos] = useState({
|
||||
facebook: "",
|
||||
twitter: "",
|
||||
instagram: "",
|
||||
youtube: "",
|
||||
tiktok: "",
|
||||
});
|
||||
|
||||
const [isLoadingCreate, setIsLoadingCreate] = useState(false);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
onLoadMaster();
|
||||
onLoadMasterSubBidangBisnis();
|
||||
}, [])
|
||||
);
|
||||
|
||||
const onLoadMaster = async () => {
|
||||
try {
|
||||
const response = await apiMasterBidangBisnis();
|
||||
setBidangBisnis(response.data);
|
||||
} catch (error) {
|
||||
setBidangBisnis([]);
|
||||
console.log("Error onLoadMasterBidangBisnis", error);
|
||||
}
|
||||
};
|
||||
|
||||
const onLoadMasterSubBidangBisnis = async () => {
|
||||
try {
|
||||
const response = await apiMasterSubBidangBisnis({});
|
||||
setSubBidangBisnis(response.data);
|
||||
} catch (error) {
|
||||
setSubBidangBisnis([]);
|
||||
console.log("Error onLoadMasterSubBidangBisnis", error);
|
||||
}
|
||||
};
|
||||
|
||||
const handlerSelectedSubBidang = ({ id }: { id: string }) => {
|
||||
const selectedList = subBidangBisnis?.filter(
|
||||
(item) => (item?.masterBidangBisnisId as any) === id
|
||||
);
|
||||
setSelectedSubBidang(selectedList as any[]);
|
||||
};
|
||||
|
||||
const handleInputValue = (phoneNumber: string) => {
|
||||
setInputValue(phoneNumber);
|
||||
const callingCode = selectedCountry?.callingCode.replace(/^\+/, "") || "";
|
||||
let fixNumber = inputValue.replace(/\s+/g, "").replace(/^0+/, "");
|
||||
const realNumber = callingCode + fixNumber;
|
||||
setData({ ...data, tlpn: realNumber });
|
||||
};
|
||||
|
||||
const handleSelectedCountry = (country: ICountry) => {
|
||||
setSelectedCountry(country);
|
||||
};
|
||||
|
||||
return (
|
||||
<NewWrapper
|
||||
footerComponent={
|
||||
<Portofolio_ButtonCreate
|
||||
id={id as string}
|
||||
data={data}
|
||||
dataMedsos={dataMedsos}
|
||||
imageUri={imageUri}
|
||||
subBidangSelected={listSubBidangSelected}
|
||||
isLoadingCreate={isLoadingCreate}
|
||||
setIsLoadingCreate={setIsLoadingCreate}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<StackCustom gap="xs">
|
||||
<InformationBox text="Lengkapi data bisnis anda." />
|
||||
|
||||
<TextInputCustom
|
||||
required
|
||||
label="Nama Bisnis"
|
||||
placeholder="Masukkan nama bisnis"
|
||||
onChangeText={(value: any) => setData({ ...data, namaBisnis: value })}
|
||||
/>
|
||||
|
||||
<SelectCustom
|
||||
label="Bidang Usaha"
|
||||
required
|
||||
data={bidangBisnis.map((item) => ({
|
||||
label: item.name,
|
||||
value: item.id,
|
||||
}))}
|
||||
value={data.masterBidangBisnisId}
|
||||
onChange={(value) => {
|
||||
const isSameBidang = data.masterBidangBisnisId === value;
|
||||
|
||||
if (!isSameBidang) {
|
||||
setListSubBidangSelected([{ id: "" }]);
|
||||
}
|
||||
|
||||
setData({ ...(data as any), masterBidangBisnisId: value });
|
||||
handlerSelectedSubBidang({ id: value as string });
|
||||
}}
|
||||
/>
|
||||
|
||||
{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 ||
|
||||
!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);
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
|
||||
<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 />
|
||||
|
||||
<View>
|
||||
<View style={{ flexDirection: "row", alignItems: "center" }}>
|
||||
<TextCustom semiBold style={{ color: MainColor.white_gray }}>
|
||||
Nomor Telepon
|
||||
</TextCustom>
|
||||
<Text style={{ color: "red" }}> *</Text>
|
||||
</View>
|
||||
<Spacing height={5} />
|
||||
<PhoneInput
|
||||
value={inputValue}
|
||||
onChangePhoneNumber={handleInputValue}
|
||||
selectedCountry={selectedCountry}
|
||||
onChangeSelectedCountry={handleSelectedCountry}
|
||||
defaultCountry="ID"
|
||||
placeholder="xxx-xxx-xxx"
|
||||
/>
|
||||
</View>
|
||||
|
||||
<Spacing />
|
||||
|
||||
<TextInputCustom
|
||||
required
|
||||
label="Alamat Bisnis"
|
||||
placeholder="Masukkan alamat bisnis"
|
||||
onChangeText={(value: any) =>
|
||||
setData({ ...data, alamatKantor: value })
|
||||
}
|
||||
/>
|
||||
|
||||
<TextAreaCustom
|
||||
label="Deskripsi Bisnis"
|
||||
placeholder="Masukkan deskripsi bisnis"
|
||||
value={data.deskripsi}
|
||||
onChangeText={(value: any) => setData({ ...data, deskripsi: value })}
|
||||
autosize
|
||||
minRows={2}
|
||||
maxRows={5}
|
||||
required
|
||||
showCount
|
||||
maxLength={1000}
|
||||
/>
|
||||
|
||||
<Spacing />
|
||||
|
||||
<InformationBox text="Upload logo bisnis anda untuk di tampilaka pada portofolio." />
|
||||
|
||||
<CenterCustom>
|
||||
<Avatar.Image
|
||||
source={imageUri ? { uri: imageUri } : DUMMY_IMAGE.dummy_image}
|
||||
size={200}
|
||||
/>
|
||||
</CenterCustom>
|
||||
|
||||
<Spacing />
|
||||
|
||||
<ButtonCenteredOnly
|
||||
icon="upload"
|
||||
onPress={() => {
|
||||
pickImage({
|
||||
setImageUri,
|
||||
});
|
||||
}}
|
||||
>
|
||||
Upload
|
||||
</ButtonCenteredOnly>
|
||||
|
||||
<Spacing height={40} />
|
||||
|
||||
<InformationBox text="Isi hanya pada sosial media yang anda miliki." />
|
||||
|
||||
<TextInputCustom
|
||||
label="Tiktok"
|
||||
placeholder="Masukkan username tiktok"
|
||||
onChangeText={(value: any) =>
|
||||
setDataMedsos({ ...dataMedsos, tiktok: value })
|
||||
}
|
||||
/>
|
||||
|
||||
<TextInputCustom
|
||||
label="Facebook"
|
||||
placeholder="Masukkan username facebook"
|
||||
onChangeText={(value: any) =>
|
||||
setDataMedsos({ ...dataMedsos, facebook: value })
|
||||
}
|
||||
/>
|
||||
|
||||
<TextInputCustom
|
||||
label="Instagram"
|
||||
placeholder="Masukkan username instagram"
|
||||
onChangeText={(value: any) =>
|
||||
setDataMedsos({ ...dataMedsos, instagram: value })
|
||||
}
|
||||
/>
|
||||
|
||||
<TextInputCustom
|
||||
label="Twitter"
|
||||
placeholder="Masukkan username twitter"
|
||||
onChangeText={(value: any) =>
|
||||
setDataMedsos({ ...dataMedsos, twitter: value })
|
||||
}
|
||||
/>
|
||||
|
||||
<TextInputCustom
|
||||
label="Youtube"
|
||||
placeholder="Masukkan username youtube"
|
||||
onChangeText={(value: any) =>
|
||||
setDataMedsos({ ...dataMedsos, youtube: value })
|
||||
}
|
||||
/>
|
||||
</StackCustom>
|
||||
</NewWrapper>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user