From 5c2e3c897968d07a32b3bc3f4233930635e2bba1 Mon Sep 17 00:00:00 2001 From: vinay kumar Date: Fri, 11 Jul 2025 12:22:33 +0530 Subject: [PATCH] Complete service api integration --- app/(tabs)/index.tsx | 8 +- app/(tabs)/service.tsx | 45 +++++++++- app/user/profile.tsx | 105 +++++++--------------- components/service/IssueSelectorModal.tsx | 1 - utils/User.ts | 37 +++++++- 5 files changed, 120 insertions(+), 76 deletions(-) diff --git a/app/(tabs)/index.tsx b/app/(tabs)/index.tsx index 6ac1ec5..180d5d5 100644 --- a/app/(tabs)/index.tsx +++ b/app/(tabs)/index.tsx @@ -97,6 +97,9 @@ export default function HomeScreen() { useLayoutEffect(() => { navigation.setOptions({ + headerStyle: { + backgroundColor: "#F3F5F8", + }, headerTitle: () => ( {model} @@ -106,7 +109,7 @@ export default function HomeScreen() { headerRight: () => ( { console.log("Support Pressed"); setIsSupportModalVisible(true); @@ -357,6 +360,9 @@ const styles = StyleSheet.create({ paddingBottom: 110, }, iconContainer: { + backgroundColor: "#FCFCFC", + }, + supportButton: { backgroundColor: "#F3F5F8", }, headerTitleContainer: { diff --git a/app/(tabs)/service.tsx b/app/(tabs)/service.tsx index c3bd639..4c0e1af 100644 --- a/app/(tabs)/service.tsx +++ b/app/(tabs)/service.tsx @@ -17,6 +17,11 @@ import * as Yup from "yup"; import ChevronRight from "../../assets/icons/chevron_rightside.svg"; import AddPhoto from "../../assets/icons/add_photo_alternate.svg"; import IssueSelectorModal from "@/components/service/IssueSelectorModal"; +import { uploadImage } from "@/utils/User"; +import api from "@/services/axiosClient"; +import { useSnackbar } from "@/contexts/Snackbar"; +import { BASE_URL } from "@/constants/config"; +import { Overlay } from "@/components/common/Overlay"; interface FormValues { serviceType: string | null; @@ -37,6 +42,7 @@ const validationSchema = Yup.object().shape({ export default function ServiceFormScreen(): JSX.Element { const [isFocus, setIsFocus] = useState(false); const [isIssueSelectorVisible, setIssueSelectorVisible] = useState(false); + const { showSnackbar } = useSnackbar(); function toggleIssueSelector() { setIssueSelectorVisible(!isIssueSelectorVisible); @@ -113,11 +119,44 @@ export default function ServiceFormScreen(): JSX.Element { ) => { - console.log(values); + try { + const uploadedPhotoUrls: string[] = []; + for (const uri of values.photos) { + const uploadedUrl = await uploadImage(uri); + uploadedPhotoUrls.push(uploadedUrl); + } + + const payload = { + service_type: values.serviceType, + issue_types: values.issues, + scheduled_time: values.date?.toISOString(), + photos: uploadedPhotoUrls, + comments: values.comments, + }; + + const response = await api.post( + `${BASE_URL}/api/v1/schedule-maintenance`, + payload + ); + + if (!response.data.success) { + throw new Error(response.data?.message || "Submission failed"); + } + + console.log("Submission successful:", response.data); + + actions.resetForm(); + showSnackbar("Service request submitted successfully", "success"); + } catch (error) { + console.error("Error during submission:", error); + showSnackbar("Failed to submit service request", "error"); + } finally { + actions.setSubmitting(false); + } }} > {({ @@ -128,6 +167,7 @@ export default function ServiceFormScreen(): JSX.Element { setFieldValue, errors, touched, + isSubmitting, }) => ( @@ -265,6 +305,7 @@ export default function ServiceFormScreen(): JSX.Element { setFieldValue("issues", selectedIssues); }} /> + {isSubmitting && } )} diff --git a/app/user/profile.tsx b/app/user/profile.tsx index 525b818..b6824da 100644 --- a/app/user/profile.tsx +++ b/app/user/profile.tsx @@ -18,17 +18,10 @@ import { logout } from "@/store/authSlice"; import * as ImagePicker from "expo-image-picker"; import { useSnackbar } from "@/contexts/Snackbar"; import { AWS, BASE_URL, USER_PROFILE } from "@/constants/config"; -import { bytesToMB, handleUpload, updateUserProfile } from "@/utils/User"; -import api from "@/services/axiosClient"; -import { PresignedUrlDataItem } from "@/utils/User"; +import { bytesToMB, updateUserProfile, uploadImage } from "@/utils/User"; import { setUserData } from "@/store/userSlice"; import { Overlay } from "@/components/common/Overlay"; -interface PresignedUrlResponse { - message: string; - data?: PresignedUrlDataItem[]; -} - export default function ProfileScreen() { const [isLangaugeModalVisible, setLanguageModalVisible] = React.useState(false); @@ -51,51 +44,6 @@ export default function ProfileScreen() { router.replace("/auth/login"); }; - const uploadImage = async (fileName: string, uri: string) => { - try { - setIsUploading(true); - const getPresignedUrl = `${BASE_URL}/api/v1/generate-presigned-urls`; - - const response = await api.post(getPresignedUrl, { - files: [fileName], - }); - - const uploadData = response?.data?.data?.[0]; - if (!uploadData) throw new Error("Presigned URL not received"); - - const { url, fields, originalFileName } = uploadData; - const presignedUrl: PresignedUrlDataItem = { - url, - fields, - originalFileName, - }; - await handleUpload(uri, presignedUrl); - - const region = AWS.REGION; - const bucketName = AWS.BUCKET_NAME; - const objectKey = presignedUrl.fields.key; - - const uploadedImageUrl = `https://s3.${region}.amazonaws.com/${bucketName}/${encodeURIComponent( - objectKey - )}`; - - console.log("Uploaded image URL:", uploadedImageUrl); - await updateUserProfile({ - profile_url: uploadedImageUrl, - mobile: mobileNumber, - }); - - dispatch(setUserData({ profile_url: uri })); - - showSnackbar("Image uploaded successfully", "success"); - } catch (error) { - console.error("Error uploading image:", error); - showSnackbar("Error uploading image", "error"); - } finally { - setIsUploading(false); - } - }; - const handlePickImage = async () => { let result = await ImagePicker.launchImageLibraryAsync({ mediaTypes: ImagePicker.MediaTypeOptions.Images, @@ -105,25 +53,40 @@ export default function ProfileScreen() { }); if (!result.canceled) { - const { uri, fileSize } = result.assets[0]; - console.log(uri, "File size:", fileSize); - if (!fileSize) { - showSnackbar("Image size is not available", "error"); - return; - } - const size = bytesToMB(fileSize); - if (size > USER_PROFILE.MAX_IMAGE_SIZE_IN_MB) { - showSnackbar( - `Image size exceeds ${USER_PROFILE.MAX_IMAGE_SIZE_IN_MB}MB limit`, - "error" - ); - throw new Error( - `Image size exceeds ${USER_PROFILE.MAX_IMAGE_SIZE_IN_MB}MB limit` - ); - } + try { + setIsUploading(true); + const { uri, fileSize } = result.assets[0]; + console.log(uri, "File size:", fileSize); + if (!fileSize) { + showSnackbar("Image size is not available", "error"); + return; + } + const size = bytesToMB(fileSize); + if (size > USER_PROFILE.MAX_IMAGE_SIZE_IN_MB) { + showSnackbar( + `Image size exceeds ${USER_PROFILE.MAX_IMAGE_SIZE_IN_MB}MB limit`, + "error" + ); + throw new Error( + `Image size exceeds ${USER_PROFILE.MAX_IMAGE_SIZE_IN_MB}MB limit` + ); + } + const uploadedImageUrl = await uploadImage(uri); - const fileName = uri.split("/").pop() || "image.jpg"; - await uploadImage(fileName, uri); + console.log("Uploaded image URL:", uploadedImageUrl); + await updateUserProfile({ + profile_url: uploadedImageUrl, + mobile: mobileNumber, + }); + + dispatch(setUserData({ profile_url: uri })); + showSnackbar("Image uploaded successfully", "success"); + } catch (error) { + console.error("Error uploading image:", error); + showSnackbar("Image upload failed", "error"); + } finally { + setIsUploading(false); + } } }; return ( diff --git a/components/service/IssueSelectorModal.tsx b/components/service/IssueSelectorModal.tsx index c9c2542..93b63d3 100644 --- a/components/service/IssueSelectorModal.tsx +++ b/components/service/IssueSelectorModal.tsx @@ -56,7 +56,6 @@ export default function IssueSelectorModal({ /> - {/* Selection Counter and Clear Button */} { + const fileName = uri.split("/").pop() || "image.jpg"; + const getPresignedUrl = `${BASE_URL}/api/v1/generate-presigned-urls`; + + const response = await api.post(getPresignedUrl, { + files: [fileName], + }); + + const uploadData = response?.data?.data?.[0]; + if (!uploadData) throw new Error("Presigned URL not received"); + + const { url, fields, originalFileName } = uploadData; + const presignedUrl: PresignedUrlDataItem = { + url, + fields, + originalFileName, + }; + await handleUpload(uri, presignedUrl); + + const region = AWS.REGION; + const bucketName = AWS.BUCKET_NAME; + const objectKey = presignedUrl.fields.key; + + const uploadedImageUrl = `https://s3.${region}.amazonaws.com/${bucketName}/${encodeURIComponent( + objectKey + )}`; + + return uploadedImageUrl; +};