refactor: Migrate Portofolio & Maps screens to NewWrapper_V2
Phase 3 Migration - Fix keyboard handling issues across 8 screens Portofolio Screens (5): - portofolio/[id]/edit-social-media.tsx: ViewWrapper → NewWrapper_V2 - portofolio/[id]/edit-logo.tsx: ViewWrapper → NewWrapper_V2 - portofolio/[id]/edit.tsx: NewWrapper → NewWrapper_V2 + fix React error - portofolio/[id]/index.tsx: ViewWrapper → NewWrapper_V2 - screens/Portofolio/ScreenPortofolioCreate.tsx: NewWrapper → NewWrapper_V2 Maps Screens (3): - screens/Maps/ScreenMapsCreate.tsx: NewWrapper → NewWrapper_V2 - screens/Maps/ScreenMapsEdit.tsx: ViewWrapper → NewWrapper_V2 - app/(application)/(user)/maps/[id]/custom-pin.tsx: ViewWrapper → NewWrapper_V2 Changes: - Add enableKeyboardHandling to all form screens - Wrap TextInputCustom/SelectCustom/TextAreaCustom with View onStartShouldSetResponder - Fix React static flag error in portofolio edit loading state - Update TASK-004 migration task file Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
@@ -8,7 +8,7 @@ import {
|
|||||||
MapCustom,
|
MapCustom,
|
||||||
Spacing,
|
Spacing,
|
||||||
StackCustom,
|
StackCustom,
|
||||||
ViewWrapper,
|
NewWrapper_V2,
|
||||||
} from "@/components";
|
} from "@/components";
|
||||||
import CenterCustom from "@/components/Center/CenterCustom";
|
import CenterCustom from "@/components/Center/CenterCustom";
|
||||||
import { router, useLocalSearchParams } from "expo-router";
|
import { router, useLocalSearchParams } from "expo-router";
|
||||||
@@ -30,7 +30,11 @@ export default function MapsCustomPin() {
|
|||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ViewWrapper footerComponent={buttonFooter}>
|
<NewWrapper_V2
|
||||||
|
enableKeyboardHandling
|
||||||
|
keyboardScrollOffset={100}
|
||||||
|
footerComponent={buttonFooter}
|
||||||
|
>
|
||||||
<StackCustom>
|
<StackCustom>
|
||||||
<InformationBox text="Pin map akan secara otomatis menampilkan logo pada porotofolio ini, jika anda ingin melakukan custom silahkan upload logo pin baru anda." />
|
<InformationBox text="Pin map akan secara otomatis menampilkan logo pada porotofolio ini, jika anda ingin melakukan custom silahkan upload logo pin baru anda." />
|
||||||
<CenterCustom>
|
<CenterCustom>
|
||||||
@@ -49,7 +53,7 @@ export default function MapsCustomPin() {
|
|||||||
</BaseBox>
|
</BaseBox>
|
||||||
<Spacing />
|
<Spacing />
|
||||||
</StackCustom>
|
</StackCustom>
|
||||||
</ViewWrapper>
|
</NewWrapper_V2>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import {
|
|||||||
BoxButtonOnFooter,
|
BoxButtonOnFooter,
|
||||||
ButtonCenteredOnly,
|
ButtonCenteredOnly,
|
||||||
ButtonCustom,
|
ButtonCustom,
|
||||||
ViewWrapper
|
NewWrapper_V2
|
||||||
} from "@/components";
|
} from "@/components";
|
||||||
import API_STRORAGE from "@/constants/base-url-api-strorage";
|
import API_STRORAGE from "@/constants/base-url-api-strorage";
|
||||||
import DIRECTORY_ID from "@/constants/directory-id";
|
import DIRECTORY_ID from "@/constants/directory-id";
|
||||||
@@ -126,7 +126,10 @@ export default function PortofolioEditLogo() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ViewWrapper footerComponent={buttonFooter}>
|
<NewWrapper_V2
|
||||||
|
contentPaddingHorizontal={16}
|
||||||
|
footerComponent={buttonFooter}
|
||||||
|
>
|
||||||
<BaseBox
|
<BaseBox
|
||||||
style={{
|
style={{
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
@@ -146,7 +149,7 @@ export default function PortofolioEditLogo() {
|
|||||||
>
|
>
|
||||||
Upload
|
Upload
|
||||||
</ButtonCenteredOnly>
|
</ButtonCenteredOnly>
|
||||||
</ViewWrapper>
|
</NewWrapper_V2>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import {
|
import {
|
||||||
BoxButtonOnFooter,
|
BoxButtonOnFooter,
|
||||||
ButtonCustom,
|
ButtonCustom,
|
||||||
|
NewWrapper_V2,
|
||||||
TextInputCustom,
|
TextInputCustom,
|
||||||
ViewWrapper,
|
|
||||||
} from "@/components";
|
} from "@/components";
|
||||||
import {
|
import {
|
||||||
apiGetOnePortofolio,
|
apiGetOnePortofolio,
|
||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
} from "@/service/api-client/api-portofolio";
|
} from "@/service/api-client/api-portofolio";
|
||||||
import { useLocalSearchParams, router } from "expo-router";
|
import { useLocalSearchParams, router } from "expo-router";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
import { View } from "react-native";
|
||||||
import Toast from "react-native-toast-message";
|
import Toast from "react-native-toast-message";
|
||||||
|
|
||||||
export default function PortofolioEditSocialMedia() {
|
export default function PortofolioEditSocialMedia() {
|
||||||
@@ -91,38 +92,52 @@ export default function PortofolioEditSocialMedia() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ViewWrapper footerComponent={buttonFooter}>
|
<NewWrapper_V2
|
||||||
<TextInputCustom
|
enableKeyboardHandling
|
||||||
value={data.tiktok}
|
keyboardScrollOffset={100}
|
||||||
onChangeText={(value) => setData({ ...data, tiktok: value })}
|
footerComponent={buttonFooter}
|
||||||
label="Tiktok"
|
>
|
||||||
placeholder="Masukkan tiktok"
|
<View onStartShouldSetResponder={() => true}>
|
||||||
/>
|
<TextInputCustom
|
||||||
<TextInputCustom
|
value={data.tiktok}
|
||||||
value={data.instagram}
|
onChangeText={(value) => setData({ ...data, tiktok: value })}
|
||||||
onChangeText={(value) => setData({ ...data, instagram: value })}
|
label="Tiktok"
|
||||||
label="Instagram"
|
placeholder="Masukkan tiktok"
|
||||||
placeholder="Masukkan instagram"
|
/>
|
||||||
/>
|
</View>
|
||||||
<TextInputCustom
|
<View onStartShouldSetResponder={() => true}>
|
||||||
value={data.facebook}
|
<TextInputCustom
|
||||||
onChangeText={(value) => setData({ ...data, facebook: value })}
|
value={data.instagram}
|
||||||
label="Facebook"
|
onChangeText={(value) => setData({ ...data, instagram: value })}
|
||||||
placeholder="Masukkan facebook"
|
label="Instagram"
|
||||||
/>
|
placeholder="Masukkan instagram"
|
||||||
<TextInputCustom
|
/>
|
||||||
value={data.twitter}
|
</View>
|
||||||
onChangeText={(value) => setData({ ...data, twitter: value })}
|
<View onStartShouldSetResponder={() => true}>
|
||||||
label="Twitter"
|
<TextInputCustom
|
||||||
placeholder="Masukkan twitter"
|
value={data.facebook}
|
||||||
/>
|
onChangeText={(value) => setData({ ...data, facebook: value })}
|
||||||
<TextInputCustom
|
label="Facebook"
|
||||||
value={data.youtube}
|
placeholder="Masukkan facebook"
|
||||||
onChangeText={(value) => setData({ ...data, youtube: value })}
|
/>
|
||||||
label="Youtube"
|
</View>
|
||||||
placeholder="Masukkan youtube"
|
<View onStartShouldSetResponder={() => true}>
|
||||||
/>
|
<TextInputCustom
|
||||||
</ViewWrapper>
|
value={data.twitter}
|
||||||
|
onChangeText={(value) => setData({ ...data, twitter: value })}
|
||||||
|
label="Twitter"
|
||||||
|
placeholder="Masukkan twitter"
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
<View onStartShouldSetResponder={() => true}>
|
||||||
|
<TextInputCustom
|
||||||
|
value={data.youtube}
|
||||||
|
onChangeText={(value) => setData({ ...data, youtube: value })}
|
||||||
|
label="Youtube"
|
||||||
|
placeholder="Masukkan youtube"
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</NewWrapper_V2>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import {
|
|||||||
BoxButtonOnFooter,
|
BoxButtonOnFooter,
|
||||||
ButtonCustom,
|
ButtonCustom,
|
||||||
CenterCustom,
|
CenterCustom,
|
||||||
NewWrapper,
|
NewWrapper_V2,
|
||||||
PhoneInputCustom,
|
PhoneInputCustom,
|
||||||
SelectCustom,
|
SelectCustom,
|
||||||
Spacing,
|
Spacing,
|
||||||
@@ -16,7 +16,11 @@ import {
|
|||||||
import ListSkeletonComponent from "@/components/_ShareComponent/ListSkeletonComponent";
|
import ListSkeletonComponent from "@/components/_ShareComponent/ListSkeletonComponent";
|
||||||
import { MainColor } from "@/constants/color-palet";
|
import { MainColor } from "@/constants/color-palet";
|
||||||
import { ICON_SIZE_XLARGE } from "@/constants/constans-value";
|
import { ICON_SIZE_XLARGE } from "@/constants/constans-value";
|
||||||
import { DEFAULT_COUNTRY, type CountryData, COUNTRIES } from "@/constants/countries";
|
import {
|
||||||
|
DEFAULT_COUNTRY,
|
||||||
|
type CountryData,
|
||||||
|
COUNTRIES,
|
||||||
|
} from "@/constants/countries";
|
||||||
import {
|
import {
|
||||||
apiMasterBidangBisnis,
|
apiMasterBidangBisnis,
|
||||||
apiMasterSubBidangBisnis,
|
apiMasterSubBidangBisnis,
|
||||||
@@ -61,7 +65,8 @@ export default function PortofolioEdit() {
|
|||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [data, setData] = useState<any>({});
|
const [data, setData] = useState<any>({});
|
||||||
const [phoneNumber, setPhoneNumber] = useState<string>("");
|
const [phoneNumber, setPhoneNumber] = useState<string>("");
|
||||||
const [selectedCountry, setSelectedCountry] = useState<CountryData>(DEFAULT_COUNTRY);
|
const [selectedCountry, setSelectedCountry] =
|
||||||
|
useState<CountryData>(DEFAULT_COUNTRY);
|
||||||
const [bidangBisnis, setBidangBisnis] = useState<
|
const [bidangBisnis, setBidangBisnis] = useState<
|
||||||
IMasterBidangBisnis[] | null
|
IMasterBidangBisnis[] | null
|
||||||
>(null);
|
>(null);
|
||||||
@@ -75,38 +80,38 @@ export default function PortofolioEdit() {
|
|||||||
|
|
||||||
function handlePhoneChange(phone: string) {
|
function handlePhoneChange(phone: string) {
|
||||||
setPhoneNumber(phone);
|
setPhoneNumber(phone);
|
||||||
|
|
||||||
// Format phone number for API
|
// Format phone number for API
|
||||||
const callingCode = selectedCountry.callingCode;
|
const callingCode = selectedCountry.callingCode;
|
||||||
let fixNumber = phone.replace(/\s+/g, "").replace(/^0+/, "");
|
let fixNumber = phone.replace(/\s+/g, "").replace(/^0+/, "");
|
||||||
|
|
||||||
// Remove country code if already present
|
// Remove country code if already present
|
||||||
if (fixNumber.startsWith(callingCode)) {
|
if (fixNumber.startsWith(callingCode)) {
|
||||||
fixNumber = fixNumber.substring(callingCode.length);
|
fixNumber = fixNumber.substring(callingCode.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove leading zero
|
// Remove leading zero
|
||||||
fixNumber = fixNumber.replace(/^0+/, "");
|
fixNumber = fixNumber.replace(/^0+/, "");
|
||||||
|
|
||||||
const realNumber = callingCode + fixNumber;
|
const realNumber = callingCode + fixNumber;
|
||||||
setData({ ...data, tlpn: realNumber });
|
setData({ ...data, tlpn: realNumber });
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleCountryChange(country: CountryData) {
|
function handleCountryChange(country: CountryData) {
|
||||||
setSelectedCountry(country);
|
setSelectedCountry(country);
|
||||||
|
|
||||||
// Re-format with new country code
|
// Re-format with new country code
|
||||||
const callingCode = country.callingCode;
|
const callingCode = country.callingCode;
|
||||||
let fixNumber = phoneNumber.replace(/\s+/g, "").replace(/^0+/, "");
|
let fixNumber = phoneNumber.replace(/\s+/g, "").replace(/^0+/, "");
|
||||||
|
|
||||||
// Remove country code if already present
|
// Remove country code if already present
|
||||||
if (fixNumber.startsWith(callingCode)) {
|
if (fixNumber.startsWith(callingCode)) {
|
||||||
fixNumber = fixNumber.substring(callingCode.length);
|
fixNumber = fixNumber.substring(callingCode.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove leading zero
|
// Remove leading zero
|
||||||
fixNumber = fixNumber.replace(/^0+/, "");
|
fixNumber = fixNumber.replace(/^0+/, "");
|
||||||
|
|
||||||
const realNumber = callingCode + fixNumber;
|
const realNumber = callingCode + fixNumber;
|
||||||
setData({ ...data, tlpn: realNumber });
|
setData({ ...data, tlpn: realNumber });
|
||||||
}
|
}
|
||||||
@@ -157,7 +162,7 @@ export default function PortofolioEdit() {
|
|||||||
const fullNumber = response.data.tlpn;
|
const fullNumber = response.data.tlpn;
|
||||||
let displayNumber = fullNumber;
|
let displayNumber = fullNumber;
|
||||||
let detectedCountry = DEFAULT_COUNTRY;
|
let detectedCountry = DEFAULT_COUNTRY;
|
||||||
|
|
||||||
// Try to detect country from calling code
|
// Try to detect country from calling code
|
||||||
for (const country of COUNTRIES) {
|
for (const country of COUNTRIES) {
|
||||||
if (fullNumber.startsWith(country.callingCode)) {
|
if (fullNumber.startsWith(country.callingCode)) {
|
||||||
@@ -166,12 +171,12 @@ export default function PortofolioEdit() {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setSelectedCountry(detectedCountry);
|
setSelectedCountry(detectedCountry);
|
||||||
|
|
||||||
// Remove leading zero if present
|
// Remove leading zero if present
|
||||||
displayNumber = displayNumber.replace(/^0+/, "");
|
displayNumber = displayNumber.replace(/^0+/, "");
|
||||||
|
|
||||||
setPhoneNumber(displayNumber);
|
setPhoneNumber(displayNumber);
|
||||||
setData({ ...response.data, tlpn: displayNumber });
|
setData({ ...response.data, tlpn: displayNumber });
|
||||||
|
|
||||||
@@ -363,161 +368,176 @@ export default function PortofolioEdit() {
|
|||||||
</BoxButtonOnFooter>
|
</BoxButtonOnFooter>
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!bidangBisnis || !subBidangBisnis) {
|
// if (!bidangBisnis || !subBidangBisnis) {
|
||||||
return (
|
// return (
|
||||||
<>
|
// <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
|
||||||
<NewWrapper>
|
// <ListSkeletonComponent height={80} />
|
||||||
<ListSkeletonComponent height={80} />
|
// </View>
|
||||||
</NewWrapper>
|
// );
|
||||||
</>
|
// }
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<NewWrapper footerComponent={buttonUpdate}>
|
<NewWrapper_V2
|
||||||
<StackCustom gap={"xs"}>
|
enableKeyboardHandling
|
||||||
<TextInputCustom
|
keyboardScrollOffset={100}
|
||||||
required
|
footerComponent={buttonUpdate}
|
||||||
label="Nama Bisnis"
|
>
|
||||||
placeholder="Masukkan nama bisnis"
|
{!bidangBisnis || !subBidangBisnis ? (
|
||||||
value={data.namaBisnis}
|
<ListSkeletonComponent height={80} />
|
||||||
onChangeText={(value: any) =>
|
) : (
|
||||||
setData({ ...data, namaBisnis: value })
|
<StackCustom gap={"xs"}>
|
||||||
}
|
<View onStartShouldSetResponder={() => true}>
|
||||||
/>
|
<TextInputCustom
|
||||||
|
|
||||||
<SelectCustom
|
|
||||||
label="Bidang Usaha"
|
|
||||||
required
|
|
||||||
data={bidangBisnis?.map((item) => ({
|
|
||||||
label: item.name,
|
|
||||||
value: item.id,
|
|
||||||
}))}
|
|
||||||
value={data.masterBidangBisnisId}
|
|
||||||
onChange={(value: any) => {
|
|
||||||
handleBidangBisnisChange(value);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{listSubBidangSelected.map((item, index) => {
|
|
||||||
// Filter data untuk select sub bidang, menghilangkan yang sudah dipilih kecuali untuk item ini sendiri
|
|
||||||
const selectedIds = listSubBidangSelected
|
|
||||||
.filter((_, i) => i !== index)
|
|
||||||
.map((s) => s.MasterSubBidangBisnis?.id)
|
|
||||||
.filter((id) => id); // Filter hanya yang memiliki id (tidak kosong)
|
|
||||||
|
|
||||||
const availableSubBidangOptions = (selectedSubBidang || [])
|
|
||||||
.filter((sub: any) => {
|
|
||||||
// Tampilkan jika ini adalah opsi yang dipilih saat ini atau belum dipilih di sub bidang lainnya
|
|
||||||
|
|
||||||
return (
|
|
||||||
sub.id === item.MasterSubBidangBisnis?.id ||
|
|
||||||
!selectedIds.includes(sub.id)
|
|
||||||
);
|
|
||||||
})
|
|
||||||
.map((sub: any) => ({
|
|
||||||
value: sub.id,
|
|
||||||
label: sub.name,
|
|
||||||
}));
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SelectCustom
|
|
||||||
key={index}
|
|
||||||
label="Sub Bidang Usaha"
|
|
||||||
required
|
required
|
||||||
data={availableSubBidangOptions}
|
label="Nama Bisnis"
|
||||||
value={item.MasterSubBidangBisnis?.id || null}
|
placeholder="Masukkan nama bisnis"
|
||||||
|
value={data.namaBisnis}
|
||||||
|
onChangeText={(value: any) =>
|
||||||
|
setData({ ...data, namaBisnis: value })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View onStartShouldSetResponder={() => true}>
|
||||||
|
<SelectCustom
|
||||||
|
label="Bidang Usaha"
|
||||||
|
required
|
||||||
|
data={bidangBisnis?.map((item) => ({
|
||||||
|
label: item.name,
|
||||||
|
value: item.id,
|
||||||
|
}))}
|
||||||
|
value={data.masterBidangBisnisId}
|
||||||
onChange={(value: any) => {
|
onChange={(value: any) => {
|
||||||
handleSubBidangChange(value, index);
|
handleBidangBisnisChange(value);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
|
||||||
})}
|
|
||||||
|
|
||||||
<CenterCustom>
|
|
||||||
<View
|
|
||||||
style={{ flexDirection: "row", alignItems: "center", gap: 10 }}
|
|
||||||
>
|
|
||||||
<ActionIcon
|
|
||||||
disabled={
|
|
||||||
selectedSubBidang.length === listSubBidangSelected.length
|
|
||||||
}
|
|
||||||
onPress={() => {
|
|
||||||
handleAddSubBidang();
|
|
||||||
}}
|
|
||||||
icon={
|
|
||||||
<Ionicons
|
|
||||||
name="add-circle-outline"
|
|
||||||
size={ICON_SIZE_XLARGE}
|
|
||||||
color={MainColor.black}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
size="xl"
|
|
||||||
/>
|
|
||||||
<ActionIcon
|
|
||||||
disabled={listSubBidangSelected.length <= 1}
|
|
||||||
onPress={() => {
|
|
||||||
handleRemoveSubBidang(listSubBidangSelected.length - 1);
|
|
||||||
}}
|
|
||||||
icon={
|
|
||||||
<Ionicons
|
|
||||||
name="remove-circle-outline"
|
|
||||||
size={ICON_SIZE_XLARGE}
|
|
||||||
color={MainColor.black}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
size="xl"
|
|
||||||
/>
|
|
||||||
</View>
|
</View>
|
||||||
</CenterCustom>
|
|
||||||
<Spacing />
|
|
||||||
|
|
||||||
<View>
|
{listSubBidangSelected.map((item, index) => {
|
||||||
<View style={{ flexDirection: "row", alignItems: "center" }}>
|
// Filter data untuk select sub bidang, menghilangkan yang sudah dipilih kecuali untuk item ini sendiri
|
||||||
<TextCustom semiBold style={{ color: MainColor.white_gray }}>
|
const selectedIds = listSubBidangSelected
|
||||||
Nomor Telepon
|
.filter((_, i) => i !== index)
|
||||||
</TextCustom>
|
.map((s) => s.MasterSubBidangBisnis?.id)
|
||||||
<Text style={{ color: "red" }}> *</Text>
|
.filter((id) => id); // Filter hanya yang memiliki id (tidak kosong)
|
||||||
|
|
||||||
|
const availableSubBidangOptions = (selectedSubBidang || [])
|
||||||
|
.filter((sub: any) => {
|
||||||
|
// Tampilkan jika ini adalah opsi yang dipilih saat ini atau belum dipilih di sub bidang lainnya
|
||||||
|
|
||||||
|
return (
|
||||||
|
sub.id === item.MasterSubBidangBisnis?.id ||
|
||||||
|
!selectedIds.includes(sub.id)
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.map((sub: any) => ({
|
||||||
|
value: sub.id,
|
||||||
|
label: sub.name,
|
||||||
|
}));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View onStartShouldSetResponder={() => true} key={index}>
|
||||||
|
<SelectCustom
|
||||||
|
label="Sub Bidang Usaha"
|
||||||
|
required
|
||||||
|
data={availableSubBidangOptions}
|
||||||
|
value={item.MasterSubBidangBisnis?.id || null}
|
||||||
|
onChange={(value: any) => {
|
||||||
|
handleSubBidangChange(value, index);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
|
||||||
|
<CenterCustom>
|
||||||
|
<View
|
||||||
|
style={{ flexDirection: "row", alignItems: "center", gap: 10 }}
|
||||||
|
>
|
||||||
|
<ActionIcon
|
||||||
|
disabled={
|
||||||
|
selectedSubBidang.length === listSubBidangSelected.length
|
||||||
|
}
|
||||||
|
onPress={() => {
|
||||||
|
handleAddSubBidang();
|
||||||
|
}}
|
||||||
|
icon={
|
||||||
|
<Ionicons
|
||||||
|
name="add-circle-outline"
|
||||||
|
size={ICON_SIZE_XLARGE}
|
||||||
|
color={MainColor.black}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
size="xl"
|
||||||
|
/>
|
||||||
|
<ActionIcon
|
||||||
|
disabled={listSubBidangSelected.length <= 1}
|
||||||
|
onPress={() => {
|
||||||
|
handleRemoveSubBidang(listSubBidangSelected.length - 1);
|
||||||
|
}}
|
||||||
|
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} />
|
||||||
|
<PhoneInputCustom
|
||||||
|
value={phoneNumber}
|
||||||
|
onChangePhoneNumber={handlePhoneChange}
|
||||||
|
selectedCountry={selectedCountry}
|
||||||
|
onChangeCountry={handleCountryChange}
|
||||||
|
placeholder="xxx-xxx-xxx"
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
<Spacing height={5} />
|
<Spacing />
|
||||||
<PhoneInputCustom
|
|
||||||
value={phoneNumber}
|
|
||||||
onChangePhoneNumber={handlePhoneChange}
|
|
||||||
selectedCountry={selectedCountry}
|
|
||||||
onChangeCountry={handleCountryChange}
|
|
||||||
placeholder="xxx-xxx-xxx"
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
<Spacing />
|
|
||||||
|
|
||||||
<TextInputCustom
|
<View onStartShouldSetResponder={() => true}>
|
||||||
required
|
<TextInputCustom
|
||||||
label="Alamat Bisnis"
|
required
|
||||||
placeholder="Masukkan alamat bisnis"
|
label="Alamat Bisnis"
|
||||||
value={data.alamatKantor}
|
placeholder="Masukkan alamat bisnis"
|
||||||
onChangeText={(value: any) =>
|
value={data.alamatKantor}
|
||||||
setData({ ...data, alamatKantor: value })
|
onChangeText={(value: any) =>
|
||||||
}
|
setData({ ...data, alamatKantor: value })
|
||||||
/>
|
}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
|
||||||
<TextAreaCustom
|
<View onStartShouldSetResponder={() => true}>
|
||||||
label="Deskripsi Bisnis"
|
<TextAreaCustom
|
||||||
placeholder="Masukkan deskripsi bisnis"
|
label="Deskripsi Bisnis"
|
||||||
value={data.deskripsi}
|
placeholder="Masukkan deskripsi bisnis"
|
||||||
onChangeText={(value: any) =>
|
value={data.deskripsi}
|
||||||
setData({ ...data, deskripsi: value })
|
onChangeText={(value: any) =>
|
||||||
}
|
setData({ ...data, deskripsi: value })
|
||||||
autosize
|
}
|
||||||
minRows={2}
|
autosize
|
||||||
maxRows={5}
|
minRows={2}
|
||||||
required
|
maxRows={5}
|
||||||
showCount
|
required
|
||||||
maxLength={1000}
|
showCount
|
||||||
/>
|
maxLength={1000}
|
||||||
<Spacing />
|
/>
|
||||||
</StackCustom>
|
</View>
|
||||||
</NewWrapper>
|
<Spacing />
|
||||||
|
</StackCustom>
|
||||||
|
)}
|
||||||
|
</NewWrapper_V2>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import {
|
|||||||
DrawerCustom,
|
DrawerCustom,
|
||||||
DummyLandscapeImage,
|
DummyLandscapeImage,
|
||||||
LoaderCustom,
|
LoaderCustom,
|
||||||
|
NewWrapper_V2,
|
||||||
Spacing,
|
Spacing,
|
||||||
StackCustom,
|
StackCustom,
|
||||||
TextCustom,
|
TextCustom,
|
||||||
@@ -12,7 +13,6 @@ import AppHeader from "@/components/_ShareComponent/AppHeader";
|
|||||||
import LeftButtonCustom from "@/components/Button/BackButton";
|
import LeftButtonCustom from "@/components/Button/BackButton";
|
||||||
import GridTwoView from "@/components/_ShareComponent/GridTwoView";
|
import GridTwoView from "@/components/_ShareComponent/GridTwoView";
|
||||||
import CustomSkeleton from "@/components/_ShareComponent/SkeletonCustom";
|
import CustomSkeleton from "@/components/_ShareComponent/SkeletonCustom";
|
||||||
import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
|
|
||||||
import { MainColor } from "@/constants/color-palet";
|
import { MainColor } from "@/constants/color-palet";
|
||||||
import { ICON_SIZE_SMALL } from "@/constants/constans-value";
|
import { ICON_SIZE_SMALL } from "@/constants/constans-value";
|
||||||
import { useAuth } from "@/hooks/use-auth";
|
import { useAuth } from "@/hooks/use-auth";
|
||||||
@@ -92,7 +92,7 @@ export default function Portofolio() {
|
|||||||
),
|
),
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<ViewWrapper>
|
<NewWrapper_V2>
|
||||||
{!data || !profileId ? (
|
{!data || !profileId ? (
|
||||||
<StackCustom>
|
<StackCustom>
|
||||||
<CustomSkeleton height={400} />
|
<CustomSkeleton height={400} />
|
||||||
@@ -125,7 +125,7 @@ export default function Portofolio() {
|
|||||||
<Spacing />
|
<Spacing />
|
||||||
</StackCustom>
|
</StackCustom>
|
||||||
)}
|
)}
|
||||||
</ViewWrapper>
|
</NewWrapper_V2>
|
||||||
|
|
||||||
{/* Drawer Komponen Eksternal */}
|
{/* Drawer Komponen Eksternal */}
|
||||||
<DrawerCustom
|
<DrawerCustom
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import NewWrapper from "@/components/_ShareComponent/NewWrapper";
|
|
||||||
import {
|
import {
|
||||||
BoxButtonOnFooter,
|
BoxButtonOnFooter,
|
||||||
ButtonCustom,
|
ButtonCustom,
|
||||||
@@ -8,6 +7,7 @@ import {
|
|||||||
TextInputCustom,
|
TextInputCustom,
|
||||||
LandscapeFrameUploaded,
|
LandscapeFrameUploaded,
|
||||||
ButtonCenteredOnly,
|
ButtonCenteredOnly,
|
||||||
|
NewWrapper_V2,
|
||||||
} from "@/components";
|
} from "@/components";
|
||||||
import { MapSelectedPlatform } from "@/components/Map/MapSelectedPlatform";
|
import { MapSelectedPlatform } from "@/components/Map/MapSelectedPlatform";
|
||||||
import DIRECTORY_ID from "@/constants/directory-id";
|
import DIRECTORY_ID from "@/constants/directory-id";
|
||||||
@@ -18,6 +18,7 @@ import { IFileData } from "@/utils/pickFile";
|
|||||||
import pickFile from "@/utils/pickFile";
|
import pickFile from "@/utils/pickFile";
|
||||||
import { router, useLocalSearchParams } from "expo-router";
|
import { router, useLocalSearchParams } from "expo-router";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
import { View } from "react-native";
|
||||||
import { LatLng } from "react-native-maps";
|
import { LatLng } from "react-native-maps";
|
||||||
import Toast from "react-native-toast-message";
|
import Toast from "react-native-toast-message";
|
||||||
|
|
||||||
@@ -142,10 +143,14 @@ export function Maps_ScreenMapsCreate() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render screen dengan NewWrapper
|
* Render screen dengan NewWrapper_V2
|
||||||
*/
|
*/
|
||||||
return (
|
return (
|
||||||
<NewWrapper footerComponent={buttonFooter}>
|
<NewWrapper_V2
|
||||||
|
enableKeyboardHandling
|
||||||
|
keyboardScrollOffset={100}
|
||||||
|
footerComponent={buttonFooter}
|
||||||
|
>
|
||||||
<InformationBox text="Tentukan lokasi pin map dengan menekan pada map." />
|
<InformationBox text="Tentukan lokasi pin map dengan menekan pada map." />
|
||||||
|
|
||||||
<BaseBox>
|
<BaseBox>
|
||||||
@@ -160,13 +165,15 @@ export function Maps_ScreenMapsCreate() {
|
|||||||
/>
|
/>
|
||||||
</BaseBox>
|
</BaseBox>
|
||||||
|
|
||||||
<TextInputCustom
|
<View onStartShouldSetResponder={() => true}>
|
||||||
required
|
<TextInputCustom
|
||||||
label="Nama Pin"
|
required
|
||||||
placeholder="Masukkan nama pin maps"
|
label="Nama Pin"
|
||||||
value={name}
|
placeholder="Masukkan nama pin maps"
|
||||||
onChangeText={setName}
|
value={name}
|
||||||
/>
|
onChangeText={setName}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
|
||||||
<Spacing height={50} />
|
<Spacing height={50} />
|
||||||
|
|
||||||
@@ -179,7 +186,7 @@ export function Maps_ScreenMapsCreate() {
|
|||||||
</ButtonCenteredOnly>
|
</ButtonCenteredOnly>
|
||||||
|
|
||||||
<Spacing height={50} />
|
<Spacing height={50} />
|
||||||
</NewWrapper>
|
</NewWrapper_V2>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
LandscapeFrameUploaded,
|
LandscapeFrameUploaded,
|
||||||
Spacing,
|
Spacing,
|
||||||
TextInputCustom,
|
TextInputCustom,
|
||||||
ViewWrapper,
|
NewWrapper_V2,
|
||||||
} from "@/components";
|
} from "@/components";
|
||||||
import CustomSkeleton from "@/components/_ShareComponent/SkeletonCustom";
|
import CustomSkeleton from "@/components/_ShareComponent/SkeletonCustom";
|
||||||
import { MapSelectedPlatform } from "@/components/Map/MapSelectedPlatform";
|
import { MapSelectedPlatform } from "@/components/Map/MapSelectedPlatform";
|
||||||
@@ -19,6 +19,7 @@ import { uploadFileService } from "@/service/upload-service";
|
|||||||
import pickFile, { IFileData } from "@/utils/pickFile";
|
import pickFile, { IFileData } from "@/utils/pickFile";
|
||||||
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
|
import { router, useFocusEffect, useLocalSearchParams } from "expo-router";
|
||||||
import { useCallback, useState } from "react";
|
import { useCallback, useState } from "react";
|
||||||
|
import { View } from "react-native";
|
||||||
import { LatLng } from "react-native-maps";
|
import { LatLng } from "react-native-maps";
|
||||||
import Toast from "react-native-toast-message";
|
import Toast from "react-native-toast-message";
|
||||||
|
|
||||||
@@ -166,7 +167,11 @@ export function Maps_ScreenMapsEdit() {
|
|||||||
: defaultRegion;
|
: defaultRegion;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ViewWrapper footerComponent={buttonFooter}>
|
<NewWrapper_V2
|
||||||
|
enableKeyboardHandling
|
||||||
|
keyboardScrollOffset={100}
|
||||||
|
footerComponent={buttonFooter}
|
||||||
|
>
|
||||||
<InformationBox text="Tentukan lokasi pin map dengan menekan pada map." />
|
<InformationBox text="Tentukan lokasi pin map dengan menekan pada map." />
|
||||||
|
|
||||||
{/* <MapSelectedPlatform
|
{/* <MapSelectedPlatform
|
||||||
@@ -191,13 +196,15 @@ export function Maps_ScreenMapsEdit() {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<TextInputCustom
|
<View onStartShouldSetResponder={() => true}>
|
||||||
required
|
<TextInputCustom
|
||||||
label="Nama Pin"
|
required
|
||||||
placeholder="Masukkan nama pin maps"
|
label="Nama Pin"
|
||||||
value={data?.namePin}
|
placeholder="Masukkan nama pin maps"
|
||||||
onChangeText={(value) => setData({ ...data, namePin: value })}
|
value={data?.namePin}
|
||||||
/>
|
onChangeText={(value) => setData({ ...data, namePin: value })}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
|
||||||
<Spacing />
|
<Spacing />
|
||||||
|
|
||||||
@@ -223,6 +230,6 @@ export function Maps_ScreenMapsEdit() {
|
|||||||
Upload
|
Upload
|
||||||
</ButtonCenteredOnly>
|
</ButtonCenteredOnly>
|
||||||
<Spacing height={50} />
|
<Spacing height={50} />
|
||||||
</ViewWrapper>
|
</NewWrapper_V2>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import {
|
|||||||
ButtonCenteredOnly,
|
ButtonCenteredOnly,
|
||||||
CenterCustom,
|
CenterCustom,
|
||||||
InformationBox,
|
InformationBox,
|
||||||
NewWrapper,
|
NewWrapper_V2,
|
||||||
PhoneInputCustom,
|
PhoneInputCustom,
|
||||||
SelectCustom,
|
SelectCustom,
|
||||||
Spacing,
|
Spacing,
|
||||||
@@ -142,7 +142,9 @@ export function ScreenPortofolioCreate() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NewWrapper
|
<NewWrapper_V2
|
||||||
|
enableKeyboardHandling
|
||||||
|
keyboardScrollOffset={100}
|
||||||
footerComponent={
|
footerComponent={
|
||||||
<Portofolio_ButtonCreate
|
<Portofolio_ButtonCreate
|
||||||
id={id as string}
|
id={id as string}
|
||||||
@@ -158,57 +160,62 @@ export function ScreenPortofolioCreate() {
|
|||||||
<StackCustom gap="xs">
|
<StackCustom gap="xs">
|
||||||
<InformationBox text="Lengkapi data bisnis anda." />
|
<InformationBox text="Lengkapi data bisnis anda." />
|
||||||
|
|
||||||
<TextInputCustom
|
<View onStartShouldSetResponder={() => true}>
|
||||||
required
|
<TextInputCustom
|
||||||
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
|
required
|
||||||
data={_.map(selectedSubBidang as any)
|
label="Nama Bisnis"
|
||||||
.filter((option: any) => {
|
placeholder="Masukkan nama bisnis"
|
||||||
const selectedValues = listSubBidangSelected.map((s) => s.id);
|
onChangeText={(value: any) => setData({ ...data, namaBisnis: value })}
|
||||||
return (
|
/>
|
||||||
option.id === item.id || !selectedValues.includes(option.id)
|
</View>
|
||||||
);
|
|
||||||
})
|
<View onStartShouldSetResponder={() => true}>
|
||||||
.map((e: any) => ({
|
<SelectCustom
|
||||||
value: e.id,
|
label="Bidang Usaha"
|
||||||
label: e.name,
|
required
|
||||||
}))}
|
data={bidangBisnis.map((item) => ({
|
||||||
value={item.id || null}
|
label: item.name,
|
||||||
|
value: item.id,
|
||||||
|
}))}
|
||||||
|
value={data.masterBidangBisnisId}
|
||||||
onChange={(value) => {
|
onChange={(value) => {
|
||||||
const list = _.clone(listSubBidangSelected);
|
const isSameBidang = data.masterBidangBisnisId === value;
|
||||||
list[index].id = value as any;
|
|
||||||
setListSubBidangSelected(list);
|
if (!isSameBidang) {
|
||||||
|
setListSubBidangSelected([{ id: "" }]);
|
||||||
|
}
|
||||||
|
|
||||||
|
setData({ ...(data as any), masterBidangBisnisId: value });
|
||||||
|
handlerSelectedSubBidang({ id: value as string });
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{listSubBidangSelected.map((item, index) => (
|
||||||
|
<View onStartShouldSetResponder={() => true} key={index}>
|
||||||
|
<SelectCustom
|
||||||
|
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);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
<CenterCustom>
|
<CenterCustom>
|
||||||
@@ -272,27 +279,31 @@ export function ScreenPortofolioCreate() {
|
|||||||
|
|
||||||
<Spacing />
|
<Spacing />
|
||||||
|
|
||||||
<TextInputCustom
|
<View onStartShouldSetResponder={() => true}>
|
||||||
required
|
<TextInputCustom
|
||||||
label="Alamat Bisnis"
|
required
|
||||||
placeholder="Masukkan alamat bisnis"
|
label="Alamat Bisnis"
|
||||||
onChangeText={(value: any) =>
|
placeholder="Masukkan alamat bisnis"
|
||||||
setData({ ...data, alamatKantor: value })
|
onChangeText={(value: any) =>
|
||||||
}
|
setData({ ...data, alamatKantor: value })
|
||||||
/>
|
}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
|
||||||
<TextAreaCustom
|
<View onStartShouldSetResponder={() => true}>
|
||||||
label="Deskripsi Bisnis"
|
<TextAreaCustom
|
||||||
placeholder="Masukkan deskripsi bisnis"
|
label="Deskripsi Bisnis"
|
||||||
value={data.deskripsi}
|
placeholder="Masukkan deskripsi bisnis"
|
||||||
onChangeText={(value: any) => setData({ ...data, deskripsi: value })}
|
value={data.deskripsi}
|
||||||
autosize
|
onChangeText={(value: any) => setData({ ...data, deskripsi: value })}
|
||||||
minRows={2}
|
autosize
|
||||||
maxRows={5}
|
minRows={2}
|
||||||
required
|
maxRows={5}
|
||||||
showCount
|
required
|
||||||
maxLength={1000}
|
showCount
|
||||||
/>
|
maxLength={1000}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
|
||||||
<Spacing />
|
<Spacing />
|
||||||
|
|
||||||
@@ -322,46 +333,56 @@ export function ScreenPortofolioCreate() {
|
|||||||
|
|
||||||
<InformationBox text="Isi hanya pada sosial media yang anda miliki." />
|
<InformationBox text="Isi hanya pada sosial media yang anda miliki." />
|
||||||
|
|
||||||
<TextInputCustom
|
<View onStartShouldSetResponder={() => true}>
|
||||||
label="Tiktok"
|
<TextInputCustom
|
||||||
placeholder="Masukkan username tiktok"
|
label="Tiktok"
|
||||||
onChangeText={(value: any) =>
|
placeholder="Masukkan username tiktok"
|
||||||
setDataMedsos({ ...dataMedsos, tiktok: value })
|
onChangeText={(value: any) =>
|
||||||
}
|
setDataMedsos({ ...dataMedsos, tiktok: value })
|
||||||
/>
|
}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
|
||||||
<TextInputCustom
|
<View onStartShouldSetResponder={() => true}>
|
||||||
label="Facebook"
|
<TextInputCustom
|
||||||
placeholder="Masukkan username facebook"
|
label="Facebook"
|
||||||
onChangeText={(value: any) =>
|
placeholder="Masukkan username facebook"
|
||||||
setDataMedsos({ ...dataMedsos, facebook: value })
|
onChangeText={(value: any) =>
|
||||||
}
|
setDataMedsos({ ...dataMedsos, facebook: value })
|
||||||
/>
|
}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
|
||||||
<TextInputCustom
|
<View onStartShouldSetResponder={() => true}>
|
||||||
label="Instagram"
|
<TextInputCustom
|
||||||
placeholder="Masukkan username instagram"
|
label="Instagram"
|
||||||
onChangeText={(value: any) =>
|
placeholder="Masukkan username instagram"
|
||||||
setDataMedsos({ ...dataMedsos, instagram: value })
|
onChangeText={(value: any) =>
|
||||||
}
|
setDataMedsos({ ...dataMedsos, instagram: value })
|
||||||
/>
|
}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
|
||||||
<TextInputCustom
|
<View onStartShouldSetResponder={() => true}>
|
||||||
label="Twitter"
|
<TextInputCustom
|
||||||
placeholder="Masukkan username twitter"
|
label="Twitter"
|
||||||
onChangeText={(value: any) =>
|
placeholder="Masukkan username twitter"
|
||||||
setDataMedsos({ ...dataMedsos, twitter: value })
|
onChangeText={(value: any) =>
|
||||||
}
|
setDataMedsos({ ...dataMedsos, twitter: value })
|
||||||
/>
|
}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
|
||||||
<TextInputCustom
|
<View onStartShouldSetResponder={() => true}>
|
||||||
label="Youtube"
|
<TextInputCustom
|
||||||
placeholder="Masukkan username youtube"
|
label="Youtube"
|
||||||
onChangeText={(value: any) =>
|
placeholder="Masukkan username youtube"
|
||||||
setDataMedsos({ ...dataMedsos, youtube: value })
|
onChangeText={(value: any) =>
|
||||||
}
|
setDataMedsos({ ...dataMedsos, youtube: value })
|
||||||
/>
|
}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
</StackCustom>
|
</StackCustom>
|
||||||
</NewWrapper>
|
</NewWrapper_V2>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,29 +15,47 @@ Migrasi bertahap dari `NewWrapper` ke `NewWrapper_V2` untuk memperbaiki bug keyb
|
|||||||
|
|
||||||
## 📊 Migration Priority
|
## 📊 Migration Priority
|
||||||
|
|
||||||
### **Phase 1: Job Screens** (Week 1) - CURRENT
|
### **Phase 1: Job Screens** (Week 1) ✅ COMPLETED
|
||||||
- [x] `screens/Job/ScreenJobCreate2.tsx` → Already using keyboard handling
|
- [x] `screens/Job/ScreenJobCreate2.tsx` → Already using keyboard handling
|
||||||
- [ ] `screens/Job/ScreenJobCreate.tsx` → Migrate to NewWrapper_V2
|
- [x] `screens/Job/ScreenJobCreate.tsx` → Migrate to NewWrapper_V2
|
||||||
- [ ] `screens/Job/ScreenJobEdit.tsx` → Migrate to NewWrapper_V2
|
- [x] `screens/Job/ScreenJobEdit.tsx` → Migrate to NewWrapper_V2
|
||||||
- [ ] Delete test files after migration
|
- [x] Delete test files after migration
|
||||||
|
|
||||||
### **Phase 2: Event & Profile Screens** (Week 2)
|
### **Phase 2: Profile Screens** (Week 2) ✅ COMPLETED
|
||||||
|
- [x] `app/(application)/(user)/profile/create.tsx` → Migrate to NewWrapper_V2
|
||||||
|
- [x] `app/(application)/(user)/profile/[id]/edit.tsx` → Migrate to NewWrapper_V2
|
||||||
|
- [x] `app/(application)/(user)/profile/[id]/index.tsx` → Migrate to NewWrapper_V2
|
||||||
|
- [x] `app/(application)/(user)/profile/[id]/detail-blocked.tsx` → Migrate to NewWrapper_V2
|
||||||
|
- [x] `app/(application)/(user)/profile/[id]/blocked-list.tsx` → Migrate to NewWrapper_V2
|
||||||
|
- [x] `app/(application)/(user)/profile/[id]/update-photo.tsx` → Migrate to NewWrapper_V2
|
||||||
|
- [x] `app/(application)/(user)/profile/[id]/update-background.tsx` → Migrate to NewWrapper_V2
|
||||||
|
|
||||||
|
### **Phase 3: Portofolio & Maps Screens** (Week 3) - NEXT
|
||||||
|
- [ ] `app/(application)/(user)/portofolio/[id]/create.tsx`
|
||||||
|
- [ ] `app/(application)/(user)/portofolio/[id]/edit.tsx`
|
||||||
|
- [ ] `app/(application)/(user)/portofolio/[id]/edit-logo.tsx`
|
||||||
|
- [ ] `app/(application)/(user)/portofolio/[id]/edit-social-media.tsx`
|
||||||
|
- [ ] `app/(application)/(user)/portofolio/[id]/index.tsx`
|
||||||
|
- [ ] `app/(application)/(user)/portofolio/[id]/list.tsx`
|
||||||
|
- [ ] `screens/Maps/ScreenMapsCreate.tsx`
|
||||||
|
- [ ] `screens/Maps/ScreenMapsEdit.tsx`
|
||||||
|
- [ ] `app/(application)/(user)/maps/[id]/custom-pin.tsx`
|
||||||
|
|
||||||
|
### **Phase 4: Event Screens** (Week 4)
|
||||||
- [ ] `screens/Event/ScreenEventCreate.tsx`
|
- [ ] `screens/Event/ScreenEventCreate.tsx`
|
||||||
- [ ] `screens/Event/ScreenEventEdit.tsx`
|
- [ ] `screens/Event/ScreenEventEdit.tsx`
|
||||||
- [ ] `screens/Profile/ScreenProfileCreate.tsx`
|
|
||||||
- [ ] `screens/Profile/ScreenProfileEdit.tsx`
|
|
||||||
|
|
||||||
### **Phase 3: Other Form Screens** (Week 3)
|
### **Phase 5: Other Form Screens** (Week 5)
|
||||||
- [ ] `screens/Donation/` - All create/edit screens
|
- [ ] `screens/Donation/` - All create/edit screens
|
||||||
- [ ] `screens/Investment/` - All create/edit screens
|
- [ ] `screens/Investment/` - All create/edit screens
|
||||||
- [ ] `screens/Voting/` - All create/edit screens
|
- [ ] `screens/Voting/` - All create/edit screens
|
||||||
|
|
||||||
### **Phase 4: Complex Screens** (Week 4)
|
### **Phase 6: Complex Screens** (Week 6)
|
||||||
- [ ] `screens/Forum/` - Create/edit with rich text
|
- [ ] `screens/Forum/` - Create/edit with rich text
|
||||||
- [ ] `screens/Collaboration/` - Complex forms
|
- [ ] `screens/Collaboration/` - Complex forms
|
||||||
- [ ] Other complex forms
|
- [ ] Other complex forms
|
||||||
|
|
||||||
### **Phase 5: Cleanup** (Week 5)
|
### **Phase 7: Cleanup** (Week 7)
|
||||||
- [ ] Remove old `NewWrapper.tsx` (or deprecate)
|
- [ ] Remove old `NewWrapper.tsx` (or deprecate)
|
||||||
- [ ] Rename `NewWrapper_V2.tsx` → `NewWrapper.tsx`
|
- [ ] Rename `NewWrapper_V2.tsx` → `NewWrapper.tsx`
|
||||||
- [ ] Update documentation
|
- [ ] Update documentation
|
||||||
@@ -214,10 +232,12 @@ import { View } from "react-native";
|
|||||||
| Phase | Screens | Status | Completed Date |
|
| Phase | Screens | Status | Completed Date |
|
||||||
|-------|---------|--------|----------------|
|
|-------|---------|--------|----------------|
|
||||||
| **Phase 1: Job** | 6 screens | ✅ COMPLETED | 2026-04-01 |
|
| **Phase 1: Job** | 6 screens | ✅ COMPLETED | 2026-04-01 |
|
||||||
| **Phase 2: Event & Profile** | 4 screens | ⏳ Pending | - |
|
| **Phase 2: Profile** | 7 screens | ✅ COMPLETED | 2026-04-04 |
|
||||||
| **Phase 3: Forms** | 6-8 screens | ⏳ Pending | - |
|
| **Phase 3: Portofolio & Maps** | 9 screens | ⏳ Pending | - |
|
||||||
| **Phase 4: Complex** | 4-6 screens | ⏳ Pending | - |
|
| **Phase 4: Event** | 2 screens | ⏳ Pending | - |
|
||||||
| **Phase 5: Cleanup** | Cleanup | ⏳ Pending | - |
|
| **Phase 5: Forms** | 6-8 screens | ⏳ Pending | - |
|
||||||
|
| **Phase 6: Complex** | 4-6 screens | ⏳ Pending | - |
|
||||||
|
| **Phase 7: Cleanup** | Cleanup | ⏳ Pending | - |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -256,30 +276,63 @@ import { View } from "react-native";
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## ✅ Phase 2: COMPLETED!
|
||||||
|
|
||||||
|
**Migrated Screens:**
|
||||||
|
1. ✅ `app/(application)/(user)/profile/create.tsx` - Form with keyboard handling
|
||||||
|
2. ✅ `app/(application)/(user)/profile/[id]/edit.tsx` - Form with keyboard handling
|
||||||
|
3. ✅ `app/(application)/(user)/profile/[id]/index.tsx` - Profile detail (list, no keyboard handling)
|
||||||
|
4. ✅ `app/(application)/(user)/profile/[id]/detail-blocked.tsx` - Blocked detail with keyboard handling
|
||||||
|
5. ✅ `app/(application)/(user)/profile/[id]/blocked-list.tsx` - Blocked list (list, no keyboard handling)
|
||||||
|
6. ✅ `app/(application)/(user)/profile/[id]/update-photo.tsx` - Photo update screen
|
||||||
|
7. ✅ `app/(application)/(user)/profile/[id]/update-background.tsx` - Background update screen
|
||||||
|
|
||||||
|
**Changes Applied:**
|
||||||
|
- Replaced `ViewWrapper`/`NewWrapper` → `NewWrapper_V2`
|
||||||
|
- Added `enableKeyboardHandling` prop to form screens
|
||||||
|
- Added `keyboardScrollOffset={100}` to form screens
|
||||||
|
- Wrapped all `TextInputCustom`/`SelectCustom` with `<View onStartShouldSetResponder={() => true}>`
|
||||||
|
- Fixed keyboard handling issues (footer lift, white area, input cutoff)
|
||||||
|
|
||||||
|
**Commits:**
|
||||||
|
- `3382c16` - refactor: Migrate Profile screens to NewWrapper_V2
|
||||||
|
- `76759cc` - chore: Update layout headers and iOS build config
|
||||||
|
|
||||||
|
**Total:** 7 screens migrated, 2 commits pushed to branch `qc/4-apr-26`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## 🚀 Current Status
|
## 🚀 Current Status
|
||||||
|
|
||||||
**Status**: 🟡 IN PROGRESS
|
**Status**: 🟡 IN PROGRESS
|
||||||
**Current Phase**: Phase 1 - Job Screens
|
**Current Phase**: Phase 2 - Profile Screens ✅ COMPLETED
|
||||||
|
**Next Phase**: Phase 3 - Portofolio & Maps Screens
|
||||||
**Started**: 2026-04-01
|
**Started**: 2026-04-01
|
||||||
**ETA**: 2026-04-07 (Phase 1 complete)
|
**Last Updated**: 2026-04-04
|
||||||
|
**Overall Progress**: 13/34+ screens completed (38%)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📞 Next Actions
|
## 📞 Next Actions
|
||||||
|
|
||||||
1. **Immediate** (Today):
|
1. **Immediate** (Today):
|
||||||
- [ ] Migrate `ScreenJobCreate.tsx`
|
- [ ] Migrate `app/(application)/(user)/portofolio/[id]/create.tsx`
|
||||||
- [ ] Migrate `ScreenJobEdit.tsx`
|
- [ ] Migrate `app/(application)/(user)/portofolio/[id]/edit.tsx`
|
||||||
- [ ] Test both screens
|
- [ ] Migrate `app/(application)/(user)/portofolio/[id]/edit-logo.tsx`
|
||||||
|
- [ ] Migrate `app/(application)/(user)/portofolio/[id]/edit-social-media.tsx`
|
||||||
|
- [ ] Migrate `screens/Maps/ScreenMapsCreate.tsx`
|
||||||
|
- [ ] Migrate `screens/Maps/ScreenMapsEdit.tsx`
|
||||||
|
- [ ] Migrate `app/(application)/(user)/maps/[id]/custom-pin.tsx`
|
||||||
|
- [ ] Test all Portofolio & Maps screens
|
||||||
|
|
||||||
2. **This Week**:
|
2. **This Week**:
|
||||||
- [ ] Delete test files
|
- [ ] Complete Phase 3 (Portofolio & Maps screens)
|
||||||
- [ ] Document any issues
|
- [ ] Document any issues
|
||||||
- [ ] Prepare Phase 2
|
- [ ] Prepare Phase 4
|
||||||
|
|
||||||
3. **Next Week**:
|
3. **Next Week**:
|
||||||
- [ ] Start Phase 2 (Event & Profile)
|
- [ ] Start Phase 4 (Event screens)
|
||||||
- [ ] Review Phase 1 results
|
- [ ] Review Phase 2-3 results
|
||||||
- [ ] Adjust migration guide if needed
|
- [ ] Adjust migration guide if needed
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -297,8 +350,13 @@ import { View } from "react-native";
|
|||||||
- `tasks/TASK-004-newwrapper-migration.md` (This file)
|
- `tasks/TASK-004-newwrapper-migration.md` (This file)
|
||||||
|
|
||||||
**Screens to Migrate:**
|
**Screens to Migrate:**
|
||||||
- `screens/Job/ScreenJobCreate.tsx`
|
- `app/(application)/(user)/portofolio/[id]/create.tsx` (Phase 3)
|
||||||
- `screens/Job/ScreenJobEdit.tsx`
|
- `app/(application)/(user)/portofolio/[id]/edit.tsx` (Phase 3)
|
||||||
|
- `app/(application)/(user)/portofolio/[id]/edit-logo.tsx` (Phase 3)
|
||||||
|
- `app/(application)/(user)/portofolio/[id]/edit-social-media.tsx` (Phase 3)
|
||||||
|
- `screens/Maps/ScreenMapsCreate.tsx` (Phase 3)
|
||||||
|
- `screens/Maps/ScreenMapsEdit.tsx` (Phase 3)
|
||||||
|
- `app/(application)/(user)/maps/[id]/custom-pin.tsx` (Phase 3)
|
||||||
- (More in subsequent phases)
|
- (More in subsequent phases)
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -322,12 +380,23 @@ import { View } from "react-native";
|
|||||||
|
|
||||||
## ✅ Success Criteria
|
## ✅ Success Criteria
|
||||||
|
|
||||||
**Phase 1 Complete when:**
|
**Phase 2 Complete when:** ✅
|
||||||
- [ ] Job Create migrated
|
- [x] Profile Create migrated
|
||||||
- [ ] Job Edit migrated
|
- [x] Profile Edit migrated
|
||||||
- [ ] Both screens tested on iOS & Android
|
- [x] Profile detail screens migrated
|
||||||
|
- [x] All screens tested
|
||||||
|
- [x] Commits pushed to branch
|
||||||
|
|
||||||
|
**Phase 3 Complete when:**
|
||||||
|
- [ ] Portofolio Create migrated
|
||||||
|
- [ ] Portofolio Edit migrated
|
||||||
|
- [ ] Portofolio edit-logo migrated
|
||||||
|
- [ ] Portofolio edit-social-media migrated
|
||||||
|
- [ ] Maps Create migrated
|
||||||
|
- [ ] Maps Edit migrated
|
||||||
|
- [ ] Maps custom-pin migrated
|
||||||
|
- [ ] All Portofolio & Maps screens tested on iOS & Android
|
||||||
- [ ] No critical bugs
|
- [ ] No critical bugs
|
||||||
- [ ] Test files deleted
|
|
||||||
- [ ] Documentation updated
|
- [ ] Documentation updated
|
||||||
|
|
||||||
**Overall Migration Complete when:**
|
**Overall Migration Complete when:**
|
||||||
@@ -339,6 +408,6 @@ import { View } from "react-native";
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**Last Updated**: 2026-04-01
|
**Last Updated**: 2026-04-04
|
||||||
**Created by**: AI Assistant
|
**Created by**: AI Assistant
|
||||||
**Status**: 🟡 IN PROGRESS
|
**Status**: 🟡 IN PROGRESS - Phase 2 Complete, Ready for Phase 3 (Portofolio & Maps)
|
||||||
|
|||||||
Reference in New Issue
Block a user