Fix:
- profile/[id]/edit.tsx: api upload
- profile/[id]/update-photo.tsx: api upload
- service/api-client/api-profile.ts: api profile bisa memilih kategori

Component
Add:
- components/Image/AvatarComp.tsx

### No Issue
This commit is contained in:
2025-08-27 12:16:31 +08:00
parent 7cddc7abe3
commit 2227aaa99f
9 changed files with 106 additions and 38 deletions

View File

@@ -1,9 +1,13 @@
import { LandscapeFrameUploaded, ViewWrapper } from "@/components";
import { ViewWrapper } from "@/components";
import API_STRORAGE from "@/constants/base-url-api-strorage";
import { Image } from "expo-image";
import { useLocalSearchParams } from "expo-router";
export default function PreviewImage() {
const { id } = useLocalSearchParams();
return (
<ViewWrapper>
<LandscapeFrameUploaded />
<Image source={API_STRORAGE.GET({ fileId: id as string })} contentFit="contain" style={{ width: "100%", height: "100%" }}/>
</ViewWrapper>
);
}

View File

@@ -39,7 +39,11 @@ export default function ProfileEdit() {
const handleUpdate = async () => {
try {
setIsLoading(true);
const response = await apiUpdateProfile({ id: id as string, data });
const response = await apiUpdateProfile({
id: id as string,
data,
category: "profile",
});
if (!response.success) {
Toast.show({
type: "info",

View File

@@ -1,15 +1,14 @@
import {
AvatarCustom,
BaseBox,
BoxButtonOnFooter,
ButtonCenteredOnly,
ButtonCustom,
ButtonCustom
} from "@/components";
import ViewWrapper from "@/components/_ShareComponent/ViewWrapper";
import API_STRORAGE from "@/constants/base-url-api-strorage";
import DIRECTORY_ID from "@/constants/directory-id";
import DUMMY_IMAGE from "@/constants/dummy-image-value";
import { apiProfile } from "@/service/api-client/api-profile";
import { apiProfile, apiUpdateProfile } from "@/service/api-client/api-profile";
import { uploadImageService } from "@/service/upload-service";
import { IProfile } from "@/types/Type-Profile";
import pickImage from "@/utils/pickImage";
@@ -53,6 +52,12 @@ export default function UpdatePhotoProfile() {
console.log("Upload res >>", JSON.stringify(response, null, 2));
if (response.success) {
const imageId = response.data.id;
await apiUpdateProfile({
id: id as string,
data: { imageId },
category: "photo",
});
router.back();
}
} catch (error) {
@@ -78,15 +83,15 @@ export default function UpdatePhotoProfile() {
);
const image = imageUri ? (
<Image source={{ uri: imageUri }} style={{ width: 200, height: 200 }} />
<Image source={{ uri: imageUri }} style={{ width: "100%", height: "100%" }} />
) : (
<AvatarCustom
size="xl"
<Image
source={
data?.imageId
? API_STRORAGE.GET({ fileId: data.imageId })
? { uri: API_STRORAGE.GET({ fileId: data.imageId }) }
: DUMMY_IMAGE.avatar
}
style={{ width: "100%", height: "100%" }}
/>
);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 395 KiB

After

Width:  |  Height:  |  Size: 40 KiB

View File

@@ -0,0 +1,59 @@
import API_STRORAGE from "@/constants/base-url-api-strorage";
import DUMMY_IMAGE from "@/constants/dummy-image-value";
import { Href, router } from "expo-router";
import { TouchableOpacity } from "react-native";
import { Avatar } from "react-native-paper";
type Size = "base" | "sm" | "md" | "lg" | "xl";
const sizeMap = {
base: 40,
sm: 60,
md: 80,
lg: 100,
xl: 120,
};
interface AvatarCompProps {
fileId?: string;
size: Size;
onPress?: () => void | any;
href?: Href | undefined | any;
}
export default function AvatarComp({
fileId,
size,
onPress,
href = `/(application)/(image)/preview-image/${fileId}`,
}: AvatarCompProps) {
const dimension = sizeMap[size];
const avatarImage = () => {
return (
<Avatar.Image
size={dimension}
source={
fileId ? { uri: API_STRORAGE.GET({ fileId }) } : DUMMY_IMAGE.avatar
}
/>
);
};
return (
<>
{onPress || href ? (
<TouchableOpacity
activeOpacity={0.9}
onPress={
href && fileId ? () => router.navigate(href as any) : onPress
}
>
{avatarImage()}
</TouchableOpacity>
) : (
avatarImage()
)}
</>
);
}

View File

@@ -14,8 +14,8 @@ type Size = "base" | "sm" | "md" | "lg" | "xl";
interface AvatarCustomProps {
source?: ImageSourcePropType;
size?: Size;
onPress?: () => void;
href?: Href | undefined;
onPress?: () => any;
href?: Href | undefined | any;
}
const sizeMap = {

View File

@@ -38,6 +38,7 @@ import StackCustom from "./Stack/StackCustom";
import SelectCustom from "./Select/SelectCustom";
// Image
import AvatarCustom from "./Image/AvatarCustom";
import AvatarComp from "./Image/AvatarComp";
import LandscapeFrameUploaded from "./Image/LandscapeFrameUploaded";
// Divider
import Divider from "./Divider/Divider";
@@ -69,6 +70,7 @@ export {
AlertDefaultSystem,
// Image
AvatarCustom,
AvatarComp,
// ShareComponent
AvatarUsernameAndOtherComponent,
// Button

View File

@@ -1,4 +1,4 @@
import { AvatarCustom, ClickableCustom } from "@/components";
import { AvatarComp, ClickableCustom } from "@/components";
import { AccentColor } from "@/constants/color-palet";
import DUMMY_IMAGE from "@/constants/dummy-image-value";
import { router } from "expo-router";
@@ -12,38 +12,30 @@ const AvatarAndBackground = ({
imageId: string;
}) => {
return (
// console.log("backgroundId", backgroundId),
// console.log("imageId", imageId),
<View style={styles.container}>
{/* Background Image */}
<ClickableCustom
onPress={() => {
router.navigate(
`/(application)/(image)/preview-image/${backgroundId}`
);
}}
>
<ImageBackground
source={DUMMY_IMAGE.background}
style={styles.backgroundImage}
resizeMode="cover"
/>
</ClickableCustom>
{/* Avatar yang sedikit keluar */}
<View style={styles.avatarOverlap}>
console.log("backgroundId", backgroundId),
(
<View style={styles.container}>
{/* Background Image */}
<ClickableCustom
onPress={() => {
router.navigate(
`/(application)/(image)/preview-image/${imageId}`
`/(application)/(image)/preview-image/${backgroundId}`
);
}}
>
<AvatarCustom source={DUMMY_IMAGE.avatar} size="lg" />
<ImageBackground
source={DUMMY_IMAGE.background}
style={styles.backgroundImage}
resizeMode="cover"
/>
</ClickableCustom>
{/* Avatar yang sedikit keluar */}
<View style={styles.avatarOverlap}>
<AvatarComp size="lg" fileId={imageId} />
</View>
</View>
</View>
)
);
};

View File

@@ -15,11 +15,13 @@ export async function apiProfile({ id }: { id: string }) {
export async function apiUpdateProfile({
id,
data,
category,
}: {
id: string;
data: any;
category: "profile" | "photo" | "background";
}) {
const response = await apiConfig.put(`/mobile/profile/${id}`, {
const response = await apiConfig.put(`/mobile/profile/${id}?category=${category}`, {
data: data,
});
return response.data;