refactor: Cleanup test files and migrate Job Detail screen
- Delete ScreenJobCreate2.tsx and ScreenJobEdit2.tsx (test files) - Delete TestWrapper.tsx and TestKeyboardInput.tsx (test components) - Delete test pages (test-keyboard.tsx, test-keyboard-bug.tsx) - Update create.tsx to use ScreenJobCreate (not test version) - Update edit.tsx to use ScreenJobEdit (not test version) - Migrate Job Detail screen to NewWrapper_V2 - Remove TestWrapper from exports - Clean up imports Phase 1 cleanup completed! Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
@@ -5,9 +5,9 @@ import {
|
|||||||
DrawerCustom,
|
DrawerCustom,
|
||||||
LoaderCustom,
|
LoaderCustom,
|
||||||
MenuDrawerDynamicGrid,
|
MenuDrawerDynamicGrid,
|
||||||
|
NewWrapper_V2,
|
||||||
Spacing,
|
Spacing,
|
||||||
StackCustom,
|
StackCustom,
|
||||||
ViewWrapper,
|
|
||||||
} from "@/components";
|
} from "@/components";
|
||||||
import AppHeader from "@/components/_ShareComponent/AppHeader";
|
import AppHeader from "@/components/_ShareComponent/AppHeader";
|
||||||
import { IconEdit } from "@/components/_Icon";
|
import { IconEdit } from "@/components/_Icon";
|
||||||
@@ -72,7 +72,7 @@ export default function JobDetailStatus() {
|
|||||||
),
|
),
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<ViewWrapper>
|
<NewWrapper_V2>
|
||||||
{isLoadData ? (
|
{isLoadData ? (
|
||||||
<LoaderCustom />
|
<LoaderCustom />
|
||||||
) : (
|
) : (
|
||||||
@@ -96,7 +96,7 @@ export default function JobDetailStatus() {
|
|||||||
<Spacing />
|
<Spacing />
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</ViewWrapper>
|
</NewWrapper_V2>
|
||||||
|
|
||||||
<DrawerCustom
|
<DrawerCustom
|
||||||
isVisible={openDrawer}
|
isVisible={openDrawer}
|
||||||
|
|||||||
@@ -1,11 +1,5 @@
|
|||||||
import { Job_ScreenEdit } from "@/screens/Job/ScreenJobEdit";
|
import { Job_ScreenEdit } from "@/screens/Job/ScreenJobEdit";
|
||||||
import { Job_ScreenEdit2 } from "@/screens/Job/ScreenJobEdit2";
|
|
||||||
|
|
||||||
export default function JobEdit() {
|
export default function JobEdit() {
|
||||||
return (
|
return <Job_ScreenEdit />;
|
||||||
<>
|
|
||||||
{/* <Job_ScreenEdit />; */}
|
|
||||||
<Job_ScreenEdit2 />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,5 @@
|
|||||||
import { Job_ScreenCreate } from "@/screens/Job/ScreenJobCreate";
|
import { Job_ScreenCreate } from "@/screens/Job/ScreenJobCreate";
|
||||||
import { Job_ScreenCreate2 } from "@/screens/Job/ScreenJobCreate2";
|
|
||||||
|
|
||||||
export default function JobCreate() {
|
export default function JobCreate() {
|
||||||
return (
|
return <Job_ScreenCreate />;
|
||||||
<>
|
|
||||||
{/* <Job_ScreenCreate /> */}
|
|
||||||
<Job_ScreenCreate2/>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,45 +0,0 @@
|
|||||||
// TestWrapper.tsx - Wrapper sederhana untuk test keyboard handling
|
|
||||||
import { MainColor } from "@/constants/color-palet";
|
|
||||||
import {
|
|
||||||
Keyboard,
|
|
||||||
KeyboardAvoidingView,
|
|
||||||
Platform,
|
|
||||||
ScrollView,
|
|
||||||
View,
|
|
||||||
} from "react-native";
|
|
||||||
import {
|
|
||||||
NativeSafeAreaViewProps,
|
|
||||||
SafeAreaView,
|
|
||||||
} from "react-native-safe-area-context";
|
|
||||||
|
|
||||||
interface TestWrapperProps {
|
|
||||||
children: React.ReactNode;
|
|
||||||
footerComponent?: React.ReactNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function TestWrapper({ children, footerComponent }: TestWrapperProps) {
|
|
||||||
return (
|
|
||||||
<KeyboardAvoidingView
|
|
||||||
behavior="padding" // ← FIX: Gunakan padding untuk iOS & Android (NOT "height" untuk Android!)
|
|
||||||
style={{ flex: 1, backgroundColor: MainColor.darkblue }}
|
|
||||||
keyboardVerticalOffset={0}
|
|
||||||
>
|
|
||||||
<ScrollView
|
|
||||||
style={{ flex: 1 }}
|
|
||||||
contentContainerStyle={{ flexGrow: 1 }}
|
|
||||||
keyboardShouldPersistTaps="handled"
|
|
||||||
>
|
|
||||||
<View style={{ flex: 1, padding: 10 }}>{children}</View>
|
|
||||||
</ScrollView>
|
|
||||||
|
|
||||||
{footerComponent && (
|
|
||||||
<SafeAreaView
|
|
||||||
edges={["bottom"]}
|
|
||||||
style={{ flex: 1, backgroundColor: MainColor.red }}
|
|
||||||
>
|
|
||||||
{footerComponent}
|
|
||||||
</SafeAreaView>
|
|
||||||
)}
|
|
||||||
</KeyboardAvoidingView>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -63,7 +63,6 @@ import DummyLandscapeImage from "./_ShareComponent/DummyLandscapeImage";
|
|||||||
import GridComponentView from "./_ShareComponent/GridSectionView";
|
import GridComponentView from "./_ShareComponent/GridSectionView";
|
||||||
import NewWrapper from "./_ShareComponent/NewWrapper";
|
import NewWrapper from "./_ShareComponent/NewWrapper";
|
||||||
import BasicWrapper from "./_ShareComponent/BasicWrapper";
|
import BasicWrapper from "./_ShareComponent/BasicWrapper";
|
||||||
import { TestWrapper } from "./_ShareComponent/TestWrapper";
|
|
||||||
import { FormWrapper } from "./_ShareComponent/FormWrapper";
|
import { FormWrapper } from "./_ShareComponent/FormWrapper";
|
||||||
import { NewWrapper_V2 } from "./_ShareComponent/NewWrapper_V2";
|
import { NewWrapper_V2 } from "./_ShareComponent/NewWrapper_V2";
|
||||||
|
|
||||||
@@ -131,7 +130,6 @@ export {
|
|||||||
Spacing,
|
Spacing,
|
||||||
NewWrapper,
|
NewWrapper,
|
||||||
BasicWrapper,
|
BasicWrapper,
|
||||||
TestWrapper,
|
|
||||||
FormWrapper,
|
FormWrapper,
|
||||||
NewWrapper_V2,
|
NewWrapper_V2,
|
||||||
// Stack
|
// Stack
|
||||||
|
|||||||
@@ -1,183 +0,0 @@
|
|||||||
import {
|
|
||||||
BoxButtonOnFooter,
|
|
||||||
ButtonCenteredOnly,
|
|
||||||
ButtonCustom,
|
|
||||||
FormWrapper,
|
|
||||||
InformationBox,
|
|
||||||
LandscapeFrameUploaded,
|
|
||||||
Spacing,
|
|
||||||
StackCustom,
|
|
||||||
TextAreaCustom,
|
|
||||||
TextInputCustom,
|
|
||||||
} from "@/components";
|
|
||||||
import { MainColor } from "@/constants/color-palet";
|
|
||||||
import DIRECTORY_ID from "@/constants/directory-id";
|
|
||||||
import { useKeyboardForm } from "@/hooks/useKeyboardForm";
|
|
||||||
import { useAuth } from "@/hooks/use-auth";
|
|
||||||
import { apiJobCreate } from "@/service/api-client/api-job";
|
|
||||||
import { uploadFileService } from "@/service/upload-service";
|
|
||||||
import pickImage from "@/utils/pickImage";
|
|
||||||
import { router } from "expo-router";
|
|
||||||
import { useState } from "react";
|
|
||||||
import { View } from "react-native";
|
|
||||||
import Toast from "react-native-toast-message";
|
|
||||||
|
|
||||||
interface JobCreateData {
|
|
||||||
title: string;
|
|
||||||
content: string;
|
|
||||||
deskripsi: string;
|
|
||||||
authorId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function Job_ScreenCreate2() {
|
|
||||||
const nextUrl = "/(application)/(user)/job/(tabs)/status?status=review";
|
|
||||||
const { user } = useAuth();
|
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
|
||||||
const [image, setImage] = useState<string | null>(null);
|
|
||||||
const [data, setData] = useState<JobCreateData>({
|
|
||||||
title: "",
|
|
||||||
content: "",
|
|
||||||
deskripsi: "",
|
|
||||||
authorId: "",
|
|
||||||
});
|
|
||||||
|
|
||||||
// Use keyboard form hook
|
|
||||||
const { scrollViewRef, createFocusHandler } = useKeyboardForm(100);
|
|
||||||
|
|
||||||
const handlerOnSubmit = async () => {
|
|
||||||
let imageId = "";
|
|
||||||
const newData = {
|
|
||||||
title: data.title,
|
|
||||||
content: data.content,
|
|
||||||
deskripsi: data.deskripsi,
|
|
||||||
authorId: user?.id,
|
|
||||||
imageId: "",
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!data.title || !data.content || !data.deskripsi || !user?.id) {
|
|
||||||
Toast.show({
|
|
||||||
type: "info",
|
|
||||||
text1: "Info",
|
|
||||||
text2: "Harap isi semua data",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
setIsLoading(true);
|
|
||||||
|
|
||||||
if (image === null || !image) {
|
|
||||||
const response = await apiJobCreate(newData);
|
|
||||||
if (response.success) {
|
|
||||||
Toast.show({
|
|
||||||
type: "success",
|
|
||||||
text1: "Berhasil",
|
|
||||||
text2: "Lowongan berhasil dibuat",
|
|
||||||
});
|
|
||||||
router.replace(nextUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const responseUploadImage = await uploadFileService({
|
|
||||||
imageUri: image,
|
|
||||||
dirId: DIRECTORY_ID.job_image,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (responseUploadImage.success) {
|
|
||||||
imageId = responseUploadImage.data.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
const fixData = {
|
|
||||||
...newData,
|
|
||||||
imageId: imageId,
|
|
||||||
};
|
|
||||||
|
|
||||||
const response = await apiJobCreate(fixData);
|
|
||||||
if (response.success) {
|
|
||||||
Toast.show({
|
|
||||||
type: "success",
|
|
||||||
text1: "Berhasil",
|
|
||||||
text2: "Lowongan berhasil dibuat",
|
|
||||||
});
|
|
||||||
router.replace(nextUrl);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.log("[ERROR]", error);
|
|
||||||
} finally {
|
|
||||||
setIsLoading(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const buttonSubmit = () => {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<BoxButtonOnFooter>
|
|
||||||
<ButtonCustom isLoading={isLoading} onPress={() => handlerOnSubmit()}>
|
|
||||||
Simpan
|
|
||||||
</ButtonCustom>
|
|
||||||
</BoxButtonOnFooter>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const onFocusHandler = createFocusHandler();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<FormWrapper footerComponent={buttonSubmit()}>
|
|
||||||
<InformationBox text="Poster atau gambar lowongan kerja bersifat opsional, tidak wajib untuk dimasukkan dan upload lah gambar yang sesuai dengan deskripsi lowongan kerja." />
|
|
||||||
|
|
||||||
<LandscapeFrameUploaded image={image as string} />
|
|
||||||
<ButtonCenteredOnly
|
|
||||||
onPress={() => {
|
|
||||||
pickImage({
|
|
||||||
setImageUri: setImage,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
icon="upload"
|
|
||||||
>
|
|
||||||
Upload
|
|
||||||
</ButtonCenteredOnly>
|
|
||||||
|
|
||||||
<Spacing />
|
|
||||||
|
|
||||||
<View onStartShouldSetResponder={() => true}>
|
|
||||||
<TextInputCustom
|
|
||||||
label="Judul Lowongan"
|
|
||||||
placeholder="Masukan Judul Lowongan Kerja"
|
|
||||||
required
|
|
||||||
value={data.title}
|
|
||||||
onChangeText={(value) => setData({ ...data, title: value })}
|
|
||||||
onFocus={onFocusHandler}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View onStartShouldSetResponder={() => true}>
|
|
||||||
<TextAreaCustom
|
|
||||||
label="Syarat & Kualifikasi"
|
|
||||||
placeholder="Masukan Syarat & Kualifikasi Lowongan Kerja"
|
|
||||||
required
|
|
||||||
showCount
|
|
||||||
maxLength={1000}
|
|
||||||
value={data.content}
|
|
||||||
onChangeText={(value) => setData({ ...data, content: value })}
|
|
||||||
onFocus={onFocusHandler}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View onStartShouldSetResponder={() => true}>
|
|
||||||
<TextAreaCustom
|
|
||||||
label="Deskripsi Lowongan"
|
|
||||||
placeholder="Masukan Deskripsi Lowongan Kerja"
|
|
||||||
required
|
|
||||||
showCount
|
|
||||||
maxLength={1000}
|
|
||||||
value={data.deskripsi}
|
|
||||||
onChangeText={(value) => setData({ ...data, deskripsi: value })}
|
|
||||||
onFocus={onFocusHandler}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
</FormWrapper>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,207 +0,0 @@
|
|||||||
/* eslint-disable react-hooks/exhaustive-deps */
|
|
||||||
import {
|
|
||||||
BaseBox,
|
|
||||||
BoxButtonOnFooter,
|
|
||||||
ButtonCenteredOnly,
|
|
||||||
ButtonCustom,
|
|
||||||
DummyLandscapeImage,
|
|
||||||
InformationBox,
|
|
||||||
LandscapeFrameUploaded,
|
|
||||||
LoaderCustom,
|
|
||||||
NewWrapper_V2,
|
|
||||||
Spacing,
|
|
||||||
StackCustom,
|
|
||||||
TextAreaCustom,
|
|
||||||
TextInputCustom,
|
|
||||||
} from "@/components";
|
|
||||||
import { AccentColor } from "@/constants/color-palet";
|
|
||||||
import DIRECTORY_ID from "@/constants/directory-id";
|
|
||||||
import { apiJobGetOne, apiJobUpdateData } from "@/service/api-client/api-job";
|
|
||||||
import { deleteFileService, uploadFileService } from "@/service/upload-service";
|
|
||||||
import pickImage from "@/utils/pickImage";
|
|
||||||
import { router, useLocalSearchParams } from "expo-router";
|
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
import { View } from "react-native";
|
|
||||||
import Toast from "react-native-toast-message";
|
|
||||||
|
|
||||||
export function Job_ScreenEdit2() {
|
|
||||||
const { id } = useLocalSearchParams();
|
|
||||||
const [data, setData] = useState<any>({
|
|
||||||
title: "",
|
|
||||||
content: "",
|
|
||||||
deskripsi: "",
|
|
||||||
});
|
|
||||||
const [isLoadData, setIsLoadData] = useState(false);
|
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
|
||||||
|
|
||||||
const [imageUri, setImageUri] = useState<string | null>(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
onLoadData();
|
|
||||||
}, [id]);
|
|
||||||
|
|
||||||
const onLoadData = async () => {
|
|
||||||
try {
|
|
||||||
setIsLoadData(true);
|
|
||||||
const response = await apiJobGetOne({ id: id as string });
|
|
||||||
if (response.success) {
|
|
||||||
setData(response.data);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.log("[ERROR]", error);
|
|
||||||
} finally {
|
|
||||||
setIsLoadData(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handlerOnUpdate = async () => {
|
|
||||||
if (!data.title || !data.content || !data.deskripsi) {
|
|
||||||
Toast.show({
|
|
||||||
type: "info",
|
|
||||||
text1: "Info",
|
|
||||||
text2: "Harap isi semua data",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
setIsLoading(true);
|
|
||||||
let newImageId = "";
|
|
||||||
|
|
||||||
if (imageUri) {
|
|
||||||
const responseUploadImage = await uploadFileService({
|
|
||||||
imageUri: imageUri,
|
|
||||||
dirId: DIRECTORY_ID.job_image,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (responseUploadImage.success) {
|
|
||||||
newImageId = responseUploadImage.data.id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data?.imageId) {
|
|
||||||
const responseDeleteImage = await deleteFileService({
|
|
||||||
id: data.imageId,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!responseDeleteImage.success) {
|
|
||||||
console.log("[ERROR DELETE IMAGE]", responseDeleteImage.message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const newData = {
|
|
||||||
title: data.title,
|
|
||||||
content: data.content,
|
|
||||||
deskripsi: data.deskripsi,
|
|
||||||
imageId: newImageId,
|
|
||||||
};
|
|
||||||
|
|
||||||
const response = await apiJobUpdateData({
|
|
||||||
id: id as string,
|
|
||||||
data: newData,
|
|
||||||
category: "edit",
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.success) {
|
|
||||||
Toast.show({
|
|
||||||
type: "success",
|
|
||||||
text1: response.message,
|
|
||||||
});
|
|
||||||
router.back();
|
|
||||||
} else {
|
|
||||||
Toast.show({
|
|
||||||
type: "info",
|
|
||||||
text1: "Info",
|
|
||||||
text2: response.message,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.log("[ERROR]", error);
|
|
||||||
} finally {
|
|
||||||
setIsLoading(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const buttonSubmit = () => {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<BoxButtonOnFooter>
|
|
||||||
<ButtonCustom isLoading={isLoading} onPress={() => handlerOnUpdate()}>
|
|
||||||
Update
|
|
||||||
</ButtonCustom>
|
|
||||||
</BoxButtonOnFooter>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<NewWrapper_V2
|
|
||||||
enableKeyboardHandling
|
|
||||||
keyboardScrollOffset={100}
|
|
||||||
footerComponent={buttonSubmit()}
|
|
||||||
>
|
|
||||||
{isLoadData ? (
|
|
||||||
<LoaderCustom />
|
|
||||||
) : (
|
|
||||||
<StackCustom gap={"xs"}>
|
|
||||||
<InformationBox text="Poster atau gambar lowongan kerja bersifat opsional, tidak wajib untuk dimasukkan dan upload lah gambar yang sesuai dengan deskripsi lowongan kerja." />
|
|
||||||
|
|
||||||
{imageUri ? (
|
|
||||||
<LandscapeFrameUploaded image={imageUri as any} />
|
|
||||||
) : (
|
|
||||||
<BaseBox>
|
|
||||||
<DummyLandscapeImage imageId={data?.imageId} />
|
|
||||||
</BaseBox>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<ButtonCenteredOnly
|
|
||||||
onPress={() => {
|
|
||||||
pickImage({
|
|
||||||
setImageUri,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
icon="upload"
|
|
||||||
>
|
|
||||||
Upload
|
|
||||||
</ButtonCenteredOnly>
|
|
||||||
|
|
||||||
<Spacing />
|
|
||||||
|
|
||||||
<View onStartShouldSetResponder={() => true}>
|
|
||||||
<TextInputCustom
|
|
||||||
label="Judul Lowongan"
|
|
||||||
placeholder="Masukan Judul Lowongan Kerja"
|
|
||||||
required
|
|
||||||
value={data.title}
|
|
||||||
onChangeText={(value) => setData({ ...data, title: value })}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View onStartShouldSetResponder={() => true}>
|
|
||||||
<TextAreaCustom
|
|
||||||
label="Syarat & Kualifikasi"
|
|
||||||
placeholder="Masukan Syarat & Kualifikasi Lowongan Kerja"
|
|
||||||
required
|
|
||||||
showCount
|
|
||||||
maxLength={1000}
|
|
||||||
value={data.content}
|
|
||||||
onChangeText={(value) => setData({ ...data, content: value })}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View onStartShouldSetResponder={() => true}>
|
|
||||||
<TextAreaCustom
|
|
||||||
label="Deskripsi Lowongan"
|
|
||||||
placeholder="Masukan Deskripsi Lowongan Kerja"
|
|
||||||
required
|
|
||||||
showCount
|
|
||||||
maxLength={1000}
|
|
||||||
value={data.deskripsi}
|
|
||||||
onChangeText={(value) => setData({ ...data, deskripsi: value })}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
</StackCustom>
|
|
||||||
)}
|
|
||||||
</NewWrapper_V2>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user