Complete service api integration

feature/app-setup
vinay kumar 2025-07-11 12:22:33 +05:30
parent 5cde8dbbc6
commit 5c2e3c8979
5 changed files with 120 additions and 76 deletions

View File

@ -97,6 +97,9 @@ export default function HomeScreen() {
useLayoutEffect(() => {
navigation.setOptions({
headerStyle: {
backgroundColor: "#F3F5F8",
},
headerTitle: () => (
<View style={styles.headerTitleContainer}>
<Text style={styles.title}>{model}</Text>
@ -106,7 +109,7 @@ export default function HomeScreen() {
headerRight: () => (
<View style={styles.rightContainer}>
<Pressable
style={styles.iconContainer}
style={styles.supportButton}
onPress={() => {
console.log("Support Pressed");
setIsSupportModalVisible(true);
@ -357,6 +360,9 @@ const styles = StyleSheet.create({
paddingBottom: 110,
},
iconContainer: {
backgroundColor: "#FCFCFC",
},
supportButton: {
backgroundColor: "#F3F5F8",
},
headerTitleContainer: {

View File

@ -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<boolean>(false);
const [isIssueSelectorVisible, setIssueSelectorVisible] = useState(false);
const { showSnackbar } = useSnackbar();
function toggleIssueSelector() {
setIssueSelectorVisible(!isIssueSelectorVisible);
@ -113,11 +119,44 @@ export default function ServiceFormScreen(): JSX.Element {
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={(
onSubmit={async (
values: FormValues,
actions: FormikHelpers<FormValues>
) => {
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,
}) => (
<View style={styles.formContainer}>
<View style={styles.inputContainer}>
@ -265,6 +305,7 @@ export default function ServiceFormScreen(): JSX.Element {
setFieldValue("issues", selectedIssues);
}}
/>
{isSubmitting && <Overlay isUploading={isSubmitting} />}
</View>
)}
</Formik>

View File

@ -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<PresignedUrlResponse>(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,6 +53,8 @@ export default function ProfileScreen() {
});
if (!result.canceled) {
try {
setIsUploading(true);
const { uri, fileSize } = result.assets[0];
console.log(uri, "File size:", fileSize);
if (!fileSize) {
@ -121,9 +71,22 @@ export default function ProfileScreen() {
`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 (

View File

@ -56,7 +56,6 @@ export default function IssueSelectorModal({
/>
</View>
{/* Selection Counter and Clear Button */}
<View style={styles.counterBar}>
<Text
style={styles.counterText}

View File

@ -1,4 +1,4 @@
import { BASE_URL } from "@/constants/config";
import { AWS, BASE_URL } from "@/constants/config";
import api from "@/services/axiosClient";
import axios from "axios";
@ -25,6 +25,11 @@ export function bytesToMB(bytes: number) {
return bytes / MB;
}
interface PresignedUrlResponse {
message: string;
data?: PresignedUrlDataItem[];
}
export const handleUpload = async (
uri: string,
presignedUrl: PresignedUrlDataItem
@ -125,3 +130,33 @@ export const updateUserProfile = ({
return api.put(`${BASE_URL}/api/v1/update-user-information`, payload);
};
export const uploadImage = async (uri: string) => {
const fileName = uri.split("/").pop() || "image.jpg";
const getPresignedUrl = `${BASE_URL}/api/v1/generate-presigned-urls`;
const response = await api.post<PresignedUrlResponse>(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;
};