Complete service api integration
parent
5cde8dbbc6
commit
5c2e3c8979
|
|
@ -97,6 +97,9 @@ export default function HomeScreen() {
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
navigation.setOptions({
|
navigation.setOptions({
|
||||||
|
headerStyle: {
|
||||||
|
backgroundColor: "#F3F5F8",
|
||||||
|
},
|
||||||
headerTitle: () => (
|
headerTitle: () => (
|
||||||
<View style={styles.headerTitleContainer}>
|
<View style={styles.headerTitleContainer}>
|
||||||
<Text style={styles.title}>{model}</Text>
|
<Text style={styles.title}>{model}</Text>
|
||||||
|
|
@ -106,7 +109,7 @@ export default function HomeScreen() {
|
||||||
headerRight: () => (
|
headerRight: () => (
|
||||||
<View style={styles.rightContainer}>
|
<View style={styles.rightContainer}>
|
||||||
<Pressable
|
<Pressable
|
||||||
style={styles.iconContainer}
|
style={styles.supportButton}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
console.log("Support Pressed");
|
console.log("Support Pressed");
|
||||||
setIsSupportModalVisible(true);
|
setIsSupportModalVisible(true);
|
||||||
|
|
@ -357,6 +360,9 @@ const styles = StyleSheet.create({
|
||||||
paddingBottom: 110,
|
paddingBottom: 110,
|
||||||
},
|
},
|
||||||
iconContainer: {
|
iconContainer: {
|
||||||
|
backgroundColor: "#FCFCFC",
|
||||||
|
},
|
||||||
|
supportButton: {
|
||||||
backgroundColor: "#F3F5F8",
|
backgroundColor: "#F3F5F8",
|
||||||
},
|
},
|
||||||
headerTitleContainer: {
|
headerTitleContainer: {
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,11 @@ import * as Yup from "yup";
|
||||||
import ChevronRight from "../../assets/icons/chevron_rightside.svg";
|
import ChevronRight from "../../assets/icons/chevron_rightside.svg";
|
||||||
import AddPhoto from "../../assets/icons/add_photo_alternate.svg";
|
import AddPhoto from "../../assets/icons/add_photo_alternate.svg";
|
||||||
import IssueSelectorModal from "@/components/service/IssueSelectorModal";
|
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 {
|
interface FormValues {
|
||||||
serviceType: string | null;
|
serviceType: string | null;
|
||||||
|
|
@ -37,6 +42,7 @@ const validationSchema = Yup.object().shape({
|
||||||
export default function ServiceFormScreen(): JSX.Element {
|
export default function ServiceFormScreen(): JSX.Element {
|
||||||
const [isFocus, setIsFocus] = useState<boolean>(false);
|
const [isFocus, setIsFocus] = useState<boolean>(false);
|
||||||
const [isIssueSelectorVisible, setIssueSelectorVisible] = useState(false);
|
const [isIssueSelectorVisible, setIssueSelectorVisible] = useState(false);
|
||||||
|
const { showSnackbar } = useSnackbar();
|
||||||
|
|
||||||
function toggleIssueSelector() {
|
function toggleIssueSelector() {
|
||||||
setIssueSelectorVisible(!isIssueSelectorVisible);
|
setIssueSelectorVisible(!isIssueSelectorVisible);
|
||||||
|
|
@ -113,11 +119,44 @@ export default function ServiceFormScreen(): JSX.Element {
|
||||||
<Formik
|
<Formik
|
||||||
initialValues={initialValues}
|
initialValues={initialValues}
|
||||||
validationSchema={validationSchema}
|
validationSchema={validationSchema}
|
||||||
onSubmit={(
|
onSubmit={async (
|
||||||
values: FormValues,
|
values: FormValues,
|
||||||
actions: FormikHelpers<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,
|
setFieldValue,
|
||||||
errors,
|
errors,
|
||||||
touched,
|
touched,
|
||||||
|
isSubmitting,
|
||||||
}) => (
|
}) => (
|
||||||
<View style={styles.formContainer}>
|
<View style={styles.formContainer}>
|
||||||
<View style={styles.inputContainer}>
|
<View style={styles.inputContainer}>
|
||||||
|
|
@ -265,6 +305,7 @@ export default function ServiceFormScreen(): JSX.Element {
|
||||||
setFieldValue("issues", selectedIssues);
|
setFieldValue("issues", selectedIssues);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
{isSubmitting && <Overlay isUploading={isSubmitting} />}
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
</Formik>
|
</Formik>
|
||||||
|
|
|
||||||
|
|
@ -18,17 +18,10 @@ import { logout } from "@/store/authSlice";
|
||||||
import * as ImagePicker from "expo-image-picker";
|
import * as ImagePicker from "expo-image-picker";
|
||||||
import { useSnackbar } from "@/contexts/Snackbar";
|
import { useSnackbar } from "@/contexts/Snackbar";
|
||||||
import { AWS, BASE_URL, USER_PROFILE } from "@/constants/config";
|
import { AWS, BASE_URL, USER_PROFILE } from "@/constants/config";
|
||||||
import { bytesToMB, handleUpload, updateUserProfile } from "@/utils/User";
|
import { bytesToMB, updateUserProfile, uploadImage } from "@/utils/User";
|
||||||
import api from "@/services/axiosClient";
|
|
||||||
import { PresignedUrlDataItem } from "@/utils/User";
|
|
||||||
import { setUserData } from "@/store/userSlice";
|
import { setUserData } from "@/store/userSlice";
|
||||||
import { Overlay } from "@/components/common/Overlay";
|
import { Overlay } from "@/components/common/Overlay";
|
||||||
|
|
||||||
interface PresignedUrlResponse {
|
|
||||||
message: string;
|
|
||||||
data?: PresignedUrlDataItem[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function ProfileScreen() {
|
export default function ProfileScreen() {
|
||||||
const [isLangaugeModalVisible, setLanguageModalVisible] =
|
const [isLangaugeModalVisible, setLanguageModalVisible] =
|
||||||
React.useState(false);
|
React.useState(false);
|
||||||
|
|
@ -51,51 +44,6 @@ export default function ProfileScreen() {
|
||||||
router.replace("/auth/login");
|
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 () => {
|
const handlePickImage = async () => {
|
||||||
let result = await ImagePicker.launchImageLibraryAsync({
|
let result = await ImagePicker.launchImageLibraryAsync({
|
||||||
mediaTypes: ImagePicker.MediaTypeOptions.Images,
|
mediaTypes: ImagePicker.MediaTypeOptions.Images,
|
||||||
|
|
@ -105,6 +53,8 @@ export default function ProfileScreen() {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!result.canceled) {
|
if (!result.canceled) {
|
||||||
|
try {
|
||||||
|
setIsUploading(true);
|
||||||
const { uri, fileSize } = result.assets[0];
|
const { uri, fileSize } = result.assets[0];
|
||||||
console.log(uri, "File size:", fileSize);
|
console.log(uri, "File size:", fileSize);
|
||||||
if (!fileSize) {
|
if (!fileSize) {
|
||||||
|
|
@ -121,9 +71,22 @@ export default function ProfileScreen() {
|
||||||
`Image size exceeds ${USER_PROFILE.MAX_IMAGE_SIZE_IN_MB}MB limit`
|
`Image size exceeds ${USER_PROFILE.MAX_IMAGE_SIZE_IN_MB}MB limit`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
const uploadedImageUrl = await uploadImage(uri);
|
||||||
|
|
||||||
const fileName = uri.split("/").pop() || "image.jpg";
|
console.log("Uploaded image URL:", uploadedImageUrl);
|
||||||
await uploadImage(fileName, uri);
|
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 (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,6 @@ export default function IssueSelectorModal({
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
{/* Selection Counter and Clear Button */}
|
|
||||||
<View style={styles.counterBar}>
|
<View style={styles.counterBar}>
|
||||||
<Text
|
<Text
|
||||||
style={styles.counterText}
|
style={styles.counterText}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { BASE_URL } from "@/constants/config";
|
import { AWS, BASE_URL } from "@/constants/config";
|
||||||
import api from "@/services/axiosClient";
|
import api from "@/services/axiosClient";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
|
||||||
|
|
@ -25,6 +25,11 @@ export function bytesToMB(bytes: number) {
|
||||||
return bytes / MB;
|
return bytes / MB;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface PresignedUrlResponse {
|
||||||
|
message: string;
|
||||||
|
data?: PresignedUrlDataItem[];
|
||||||
|
}
|
||||||
|
|
||||||
export const handleUpload = async (
|
export const handleUpload = async (
|
||||||
uri: string,
|
uri: string,
|
||||||
presignedUrl: PresignedUrlDataItem
|
presignedUrl: PresignedUrlDataItem
|
||||||
|
|
@ -125,3 +130,33 @@ export const updateUserProfile = ({
|
||||||
|
|
||||||
return api.put(`${BASE_URL}/api/v1/update-user-information`, payload);
|
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;
|
||||||
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue