enh
This commit is contained in:
parent
10d13408d3
commit
b2a35176dd
8 changed files with 264 additions and 161 deletions
|
|
@ -1,25 +1,58 @@
|
||||||
import React, { useState } from "react";
|
import React, { useState, useCallback, useMemo } from "react";
|
||||||
import { View, Text, TouchableOpacity, Alert } from "react-native";
|
import { View, TouchableOpacity, Alert, ActivityIndicator } from "react-native";
|
||||||
import { tw, ConfirmationDialog, MyText, MyFlatList, useMarkDataFetchers, usePagination, ImageViewerURI } from "common-ui";
|
import { MaterialIcons } from "@expo/vector-icons";
|
||||||
|
import { useRouter } from "expo-router";
|
||||||
|
import { tw, ConfirmationDialog, MyText, MyFlatList, useMarkDataFetchers, ImageViewerURI } from "common-ui";
|
||||||
import { trpc } from "@/src/trpc-client";
|
import { trpc } from "@/src/trpc-client";
|
||||||
|
|
||||||
export default function Complaints() {
|
export default function Complaints() {
|
||||||
const { currentPage, pageSize, PaginationComponent } = usePagination(5); // 5 complaints per page for testing
|
const router = useRouter();
|
||||||
const { data, isLoading, error, refetch } = trpc.admin.complaint.getAll.useQuery({
|
const [dialogOpen, setDialogOpen] = useState(false);
|
||||||
page: currentPage,
|
const [selectedComplaintId, setSelectedComplaintId] = useState<number | null>(null);
|
||||||
limit: pageSize,
|
|
||||||
});
|
const {
|
||||||
const resolveComplaint = trpc.admin.complaint.resolve.useMutation();
|
data,
|
||||||
|
isLoading,
|
||||||
|
isError,
|
||||||
|
error,
|
||||||
|
fetchNextPage,
|
||||||
|
hasNextPage,
|
||||||
|
isFetchingNextPage,
|
||||||
|
refetch,
|
||||||
|
} = trpc.admin.complaint.getAll.useInfiniteQuery(
|
||||||
|
{ limit: 20 },
|
||||||
|
{
|
||||||
|
getNextPageParam: (lastPage) => lastPage.nextCursor,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
useMarkDataFetchers(() => {
|
useMarkDataFetchers(() => {
|
||||||
refetch();
|
refetch();
|
||||||
});
|
});
|
||||||
|
|
||||||
const [dialogOpen, setDialogOpen] = useState(false);
|
const resolveComplaint = trpc.admin.complaint.resolve.useMutation();
|
||||||
const [selectedComplaintId, setSelectedComplaintId] = useState<number | null>(null);
|
|
||||||
|
|
||||||
const complaints = data?.complaints || [];
|
const complaints = useMemo(() => {
|
||||||
const totalCount = data?.totalCount || 0;
|
const allComplaints = data?.pages.flatMap((page) => page.complaints) || [];
|
||||||
|
return allComplaints.filter(
|
||||||
|
(complaint, index, self) =>
|
||||||
|
index === self.findIndex((c) => c.id === complaint.id)
|
||||||
|
);
|
||||||
|
}, [data]);
|
||||||
|
|
||||||
|
const handleLoadMore = useCallback(() => {
|
||||||
|
if (hasNextPage && !isFetchingNextPage) {
|
||||||
|
fetchNextPage();
|
||||||
|
}
|
||||||
|
}, [hasNextPage, isFetchingNextPage, fetchNextPage]);
|
||||||
|
|
||||||
|
const handleUserPress = useCallback((userId: number) => {
|
||||||
|
router.push(`/(drawer)/user-management/${userId}`);
|
||||||
|
}, [router]);
|
||||||
|
|
||||||
|
const handleOrderPress = useCallback((orderId: number) => {
|
||||||
|
router.push(`/(drawer)/manage-orders/order-details/${orderId}`);
|
||||||
|
}, [router]);
|
||||||
|
|
||||||
const handleMarkResolved = (id: number) => {
|
const handleMarkResolved = (id: number) => {
|
||||||
setSelectedComplaintId(id);
|
setSelectedComplaintId(id);
|
||||||
|
|
@ -50,109 +83,158 @@ export default function Complaints() {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return (
|
return (
|
||||||
<View style={tw`flex-1 justify-center items-center`}>
|
<View style={tw`flex-1 justify-center items-center bg-gray-50`}>
|
||||||
<MyText style={tw`text-gray-600`}>Loading complaints...</MyText>
|
<ActivityIndicator size="large" color="#3B82F6" />
|
||||||
</View>
|
<MyText style={tw`text-gray-500 mt-4`}>Loading complaints...</MyText>
|
||||||
);
|
</View>
|
||||||
}
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (error) {
|
if (isError) {
|
||||||
return (
|
return (
|
||||||
<View style={tw`flex-1 justify-center items-center`}>
|
<View style={tw`flex-1 justify-center items-center bg-gray-50 p-6`}>
|
||||||
<MyText style={tw`text-red-600`}>Error loading complaints</MyText>
|
<MaterialIcons name="error-outline" size={48} color="#EF4444" />
|
||||||
</View>
|
<MyText style={tw`text-gray-900 text-lg font-bold mt-4`}>Error</MyText>
|
||||||
);
|
<MyText style={tw`text-gray-500 text-center mt-2 mb-6`}>
|
||||||
}
|
{error?.message || "Failed to load complaints"}
|
||||||
|
</MyText>
|
||||||
|
<TouchableOpacity
|
||||||
|
onPress={() => refetch()}
|
||||||
|
style={tw`bg-blue-600 px-6 py-3 rounded-full`}
|
||||||
|
>
|
||||||
|
<MyText style={tw`text-white font-semibold`}>Retry</MyText>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={tw`flex-1`}>
|
<View style={tw`flex-1 bg-gray-50`}>
|
||||||
<MyFlatList
|
<MyFlatList
|
||||||
style={tw`flex-1 bg-white`}
|
style={tw`flex-1`}
|
||||||
contentContainerStyle={tw`px-4 pb-6`}
|
contentContainerStyle={tw`px-4 py-4`}
|
||||||
data={complaints}
|
data={complaints}
|
||||||
keyExtractor={(item) => item.id.toString()}
|
keyExtractor={(item) => item.id.toString()}
|
||||||
renderItem={({ item }) => (
|
onEndReached={handleLoadMore}
|
||||||
<View style={tw`bg-white p-4 mb-4 rounded-2xl shadow-lg`}>
|
onEndReachedThreshold={0.5}
|
||||||
<MyText style={tw`text-lg font-bold mb-2 text-gray-800`}>Complaint #{item.id}</MyText>
|
renderItem={({ item }) => (
|
||||||
<MyText style={tw`text-base mb-2 text-gray-700`}>{item.text}</MyText>
|
<View style={tw`bg-white p-4 mb-4 rounded-2xl shadow-sm border border-gray-100`}>
|
||||||
|
<View style={tw`flex-row justify-between items-start mb-2`}>
|
||||||
|
<MyText style={tw`text-lg font-bold text-gray-900`}>
|
||||||
|
Complaint #{item.id}
|
||||||
|
</MyText>
|
||||||
|
<View
|
||||||
|
style={tw`px-2.5 py-1 rounded-full ${
|
||||||
|
item.status === "resolved"
|
||||||
|
? "bg-green-100 border border-green-200"
|
||||||
|
: "bg-amber-100 border border-amber-200"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<MyText
|
||||||
|
style={tw`text-xs font-semibold ${
|
||||||
|
item.status === "resolved" ? "text-green-700" : "text-amber-700"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{item.status === "resolved" ? "Resolved" : "Pending"}
|
||||||
|
</MyText>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
{item.images && item.images.length > 0 && (
|
<MyText style={tw`text-base text-gray-700 mb-3 leading-5`}>
|
||||||
<View style={tw`mt-3 mb-3`}>
|
{item.text}
|
||||||
<MyText style={tw`text-sm font-semibold text-gray-700 mb-2`}>Attached Images:</MyText>
|
</MyText>
|
||||||
<View style={tw`flex-row flex-wrap gap-2`}>
|
|
||||||
{item.images.map((imageUri: string, index: number) => (
|
{item.images && item.images.length > 0 && (
|
||||||
<ImageViewerURI
|
<View style={tw`mb-3`}>
|
||||||
key={index}
|
<MyText style={tw`text-sm font-semibold text-gray-700 mb-2`}>
|
||||||
uri={imageUri}
|
Attached Images:
|
||||||
style={tw`w-16 h-16 rounded-lg border border-gray-200`}
|
</MyText>
|
||||||
/>
|
<View style={tw`flex-row flex-wrap gap-2`}>
|
||||||
))}
|
{item.images.map((imageUri: string, index: number) => (
|
||||||
</View>
|
<ImageViewerURI
|
||||||
|
key={index}
|
||||||
|
uri={imageUri}
|
||||||
|
style={tw`w-16 h-16 rounded-lg border border-gray-200`}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
</View>
|
</View>
|
||||||
)}
|
</View>
|
||||||
|
)}
|
||||||
|
|
||||||
<View style={tw`flex-row items-center mb-2`}>
|
<View style={tw`flex-row items-center gap-2 mb-3`}>
|
||||||
<TouchableOpacity
|
<MaterialIcons name="person" size={14} color="#6B7280" />
|
||||||
onPress={() =>
|
<TouchableOpacity
|
||||||
Alert.alert("User Page", "User page coming soon")
|
onPress={() => item.userId && handleUserPress(item.userId)}
|
||||||
}
|
>
|
||||||
>
|
<MyText style={tw`text-sm text-blue-600 underline`}>
|
||||||
<MyText style={tw`text-sm text-blue-600 underline`}>
|
{item.userName || item.userMobile || "Unknown User"}
|
||||||
{item.userName}
|
</MyText>
|
||||||
</MyText>
|
</TouchableOpacity>
|
||||||
</TouchableOpacity>
|
{item.orderId && (
|
||||||
<MyText style={tw`text-sm text-gray-600 mx-2`}>|</MyText>
|
<>
|
||||||
{item.orderId && (
|
<MyText style={tw`text-sm text-gray-400`}>|</MyText>
|
||||||
<TouchableOpacity
|
<MaterialIcons name="shopping-bag" size={14} color="#6B7280" />
|
||||||
onPress={() =>
|
<TouchableOpacity
|
||||||
Alert.alert("Order Page", "Order page coming soon")
|
onPress={() => item.orderId && handleOrderPress(item.orderId)}
|
||||||
}
|
>
|
||||||
>
|
<MyText style={tw`text-sm text-blue-600 underline`}>
|
||||||
<MyText style={tw`text-sm text-blue-600 underline`}>
|
Order #{item.orderId}
|
||||||
Order #{item.orderId}
|
</MyText>
|
||||||
</MyText>
|
</TouchableOpacity>
|
||||||
</TouchableOpacity>
|
</>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
<MyText
|
|
||||||
style={tw`text-sm ${
|
{item.status === "pending" && (
|
||||||
item.status === "resolved" ? "text-green-600" : "text-red-600"
|
<TouchableOpacity
|
||||||
}`}
|
onPress={() => handleMarkResolved(item.id)}
|
||||||
>
|
style={tw`bg-blue-500 py-3 rounded-xl items-center shadow-sm mt-2`}
|
||||||
Status: {item.status}
|
>
|
||||||
</MyText>
|
<MyText style={tw`text-white font-semibold`}>
|
||||||
{item.status === "pending" && (
|
Resolve Complaint
|
||||||
<TouchableOpacity
|
</MyText>
|
||||||
onPress={() => handleMarkResolved(item.id)}
|
</TouchableOpacity>
|
||||||
style={tw`mt-2 bg-blue-500 p-3 rounded-lg shadow-md`}
|
)}
|
||||||
>
|
|
||||||
<MyText style={tw`text-white text-center font-semibold`}>Mark as Resolved</MyText>
|
|
||||||
</TouchableOpacity>
|
|
||||||
)}
|
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
ListEmptyComponent={
|
ListEmptyComponent={
|
||||||
<View style={tw`flex-1 justify-center items-center py-10`}>
|
<View style={tw`flex-1 justify-center items-center py-20`}>
|
||||||
<MyText style={tw`text-gray-500 text-center`}>No complaints found</MyText>
|
<View style={tw`bg-white p-6 rounded-full shadow-sm mb-4`}>
|
||||||
</View>
|
<MaterialIcons name="inbox" size={48} color="#D1D5DB" />
|
||||||
}
|
</View>
|
||||||
/>
|
<MyText style={tw`text-gray-900 text-lg font-bold`}>
|
||||||
<PaginationComponent totalCount={totalCount} />
|
No complaints
|
||||||
<ConfirmationDialog
|
</MyText>
|
||||||
open={dialogOpen}
|
<MyText style={tw`text-gray-500 text-center mt-2`}>
|
||||||
positiveAction={handleConfirmResolve}
|
All complaints will appear here
|
||||||
commentNeeded={true}
|
</MyText>
|
||||||
negativeAction={() => {
|
</View>
|
||||||
setDialogOpen(false);
|
}
|
||||||
setSelectedComplaintId(null);
|
ListFooterComponent={
|
||||||
}}
|
isFetchingNextPage ? (
|
||||||
title="Mark as Resolved"
|
<View style={tw`py-4 items-center flex-row justify-center`}>
|
||||||
message="Add admin notes for this resolution:"
|
<ActivityIndicator size="small" color="#3B82F6" />
|
||||||
confirmText="Resolve"
|
<MyText style={tw`text-gray-500 ml-2`}>Loading more...</MyText>
|
||||||
cancelText="Cancel"
|
</View>
|
||||||
/>
|
) : null
|
||||||
</View>
|
}
|
||||||
|
/>
|
||||||
|
<ConfirmationDialog
|
||||||
|
open={dialogOpen}
|
||||||
|
positiveAction={handleConfirmResolve}
|
||||||
|
commentNeeded={true}
|
||||||
|
negativeAction={() => {
|
||||||
|
setDialogOpen(false);
|
||||||
|
setSelectedComplaintId(null);
|
||||||
|
}}
|
||||||
|
title="Resolve Complaint"
|
||||||
|
message="Add admin notes for this resolution:"
|
||||||
|
confirmText="Resolve"
|
||||||
|
cancelText="Cancel"
|
||||||
|
isLoading={resolveComplaint.isPending}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -267,6 +267,23 @@ export default function OrderDetails() {
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
|
{/* Cancellation Reason */}
|
||||||
|
{order.status === "cancelled" && order.cancelReason && (
|
||||||
|
<View
|
||||||
|
style={tw`bg-red-50 p-5 rounded-2xl border border-red-100 mb-4`}
|
||||||
|
>
|
||||||
|
<View style={tw`flex-row items-center mb-2`}>
|
||||||
|
<MaterialIcons name="cancel" size={18} color="#DC2626" />
|
||||||
|
<MyText style={tw`text-sm font-bold text-red-800 ml-2`}>
|
||||||
|
Cancellation Reason
|
||||||
|
</MyText>
|
||||||
|
</View>
|
||||||
|
<MyText style={tw`text-sm text-red-900 leading-5`}>
|
||||||
|
{order.cancelReason}
|
||||||
|
</MyText>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Order Progress (Simplified Timeline) */}
|
{/* Order Progress (Simplified Timeline) */}
|
||||||
{order.status !== "cancelled" && (
|
{order.status !== "cancelled" && (
|
||||||
<View
|
<View
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,9 @@ interface OrderType {
|
||||||
readableId: number;
|
readableId: number;
|
||||||
customerName: string | null;
|
customerName: string | null;
|
||||||
address: string;
|
address: string;
|
||||||
|
addressId: number;
|
||||||
|
latitude: number | null;
|
||||||
|
longitude: number | null;
|
||||||
totalAmount: number;
|
totalAmount: number;
|
||||||
deliveryCharge: number;
|
deliveryCharge: number;
|
||||||
items: {
|
items: {
|
||||||
|
|
@ -359,11 +362,11 @@ const OrderItem = ({ order, refetch }: { order: OrderType; refetch: () => void }
|
||||||
isDelivered: order.isDelivered,
|
isDelivered: order.isDelivered,
|
||||||
isFlashDelivery: order.isFlashDelivery,
|
isFlashDelivery: order.isFlashDelivery,
|
||||||
address: order.address,
|
address: order.address,
|
||||||
addressId: 0,
|
addressId: order.addressId,
|
||||||
adminNotes: order.adminNotes,
|
adminNotes: order.adminNotes,
|
||||||
userNotes: order.userNotes,
|
userNotes: order.userNotes,
|
||||||
latitude: null,
|
latitude: order.latitude,
|
||||||
longitude: null,
|
longitude: order.longitude,
|
||||||
status: order.status,
|
status: order.status,
|
||||||
}}
|
}}
|
||||||
onViewDetails={handleMenuOption}
|
onViewDetails={handleMenuOption}
|
||||||
|
|
@ -377,7 +380,7 @@ const OrderItem = ({ order, refetch }: { order: OrderType; refetch: () => void }
|
||||||
setMenuOpen(false);
|
setMenuOpen(false);
|
||||||
setCancelDialogOpen(true);
|
setCancelDialogOpen(true);
|
||||||
}}
|
}}
|
||||||
onAttachLocation={() => {}}
|
onAttachLocation={() => refetch()}
|
||||||
onWhatsApp={() => {}}
|
onWhatsApp={() => {}}
|
||||||
onDial={() => {}}
|
onDial={() => {}}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -2,47 +2,45 @@ import { router, protectedProcedure } from '../trpc-index';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import { db } from '../../db/db_index';
|
import { db } from '../../db/db_index';
|
||||||
import { complaints, users } from '../../db/schema';
|
import { complaints, users } from '../../db/schema';
|
||||||
import { eq, desc } from 'drizzle-orm';
|
import { eq, desc, lt, and } from 'drizzle-orm';
|
||||||
import { generateSignedUrlsFromS3Urls } from '../../lib/s3-client';
|
import { generateSignedUrlsFromS3Urls } from '../../lib/s3-client';
|
||||||
|
|
||||||
export const complaintRouter = router({
|
export const complaintRouter = router({
|
||||||
getAll: protectedProcedure
|
getAll: protectedProcedure
|
||||||
.input(z.object({
|
.input(z.object({
|
||||||
page: z.number().optional().default(1),
|
cursor: z.number().optional(),
|
||||||
limit: z.number().optional().default(10),
|
limit: z.number().default(20),
|
||||||
}))
|
}))
|
||||||
.query(async ({ input }) => {
|
.query(async ({ input }) => {
|
||||||
const page = input.page;
|
const { cursor, limit } = input;
|
||||||
const limit = input.limit;
|
|
||||||
const offset = (page - 1) * limit;
|
|
||||||
|
|
||||||
const [complaintsData, totalCountResult] = await Promise.all([
|
let whereCondition = cursor
|
||||||
db
|
? lt(complaints.id, cursor)
|
||||||
.select({
|
: undefined;
|
||||||
id: complaints.id,
|
|
||||||
complaintBody: complaints.complaintBody,
|
|
||||||
userId: complaints.userId,
|
|
||||||
orderId: complaints.orderId,
|
|
||||||
isResolved: complaints.isResolved,
|
|
||||||
createdAt: complaints.createdAt,
|
|
||||||
userName: users.name,
|
|
||||||
images: complaints.images,
|
|
||||||
})
|
|
||||||
.from(complaints)
|
|
||||||
.leftJoin(users, eq(complaints.userId, users.id))
|
|
||||||
.orderBy(desc(complaints.createdAt))
|
|
||||||
.limit(limit)
|
|
||||||
.offset(offset),
|
|
||||||
db
|
|
||||||
.select({ count: db.$count(complaints) })
|
|
||||||
.from(complaints),
|
|
||||||
]);
|
|
||||||
|
|
||||||
const totalCount = totalCountResult[0].count;
|
const complaintsData = await db
|
||||||
|
.select({
|
||||||
|
id: complaints.id,
|
||||||
|
complaintBody: complaints.complaintBody,
|
||||||
|
userId: complaints.userId,
|
||||||
|
orderId: complaints.orderId,
|
||||||
|
isResolved: complaints.isResolved,
|
||||||
|
createdAt: complaints.createdAt,
|
||||||
|
userName: users.name,
|
||||||
|
userMobile: users.mobile,
|
||||||
|
images: complaints.images,
|
||||||
|
})
|
||||||
|
.from(complaints)
|
||||||
|
.leftJoin(users, eq(complaints.userId, users.id))
|
||||||
|
.where(whereCondition)
|
||||||
|
.orderBy(desc(complaints.id))
|
||||||
|
.limit(limit + 1);
|
||||||
|
|
||||||
|
const hasMore = complaintsData.length > limit;
|
||||||
|
const complaintsToReturn = hasMore ? complaintsData.slice(0, limit) : complaintsData;
|
||||||
|
|
||||||
// Generate signed URLs for images
|
|
||||||
const complaintsWithSignedImages = await Promise.all(
|
const complaintsWithSignedImages = await Promise.all(
|
||||||
complaintsData.map(async (c) => {
|
complaintsToReturn.map(async (c) => {
|
||||||
const signedImages = c.images
|
const signedImages = c.images
|
||||||
? await generateSignedUrlsFromS3Urls(c.images as string[])
|
? await generateSignedUrlsFromS3Urls(c.images as string[])
|
||||||
: [];
|
: [];
|
||||||
|
|
@ -52,6 +50,7 @@ export const complaintRouter = router({
|
||||||
text: c.complaintBody,
|
text: c.complaintBody,
|
||||||
userId: c.userId,
|
userId: c.userId,
|
||||||
userName: c.userName,
|
userName: c.userName,
|
||||||
|
userMobile: c.userMobile,
|
||||||
orderId: c.orderId,
|
orderId: c.orderId,
|
||||||
status: c.isResolved ? 'resolved' : 'pending',
|
status: c.isResolved ? 'resolved' : 'pending',
|
||||||
createdAt: c.createdAt,
|
createdAt: c.createdAt,
|
||||||
|
|
@ -62,7 +61,9 @@ export const complaintRouter = router({
|
||||||
|
|
||||||
return {
|
return {
|
||||||
complaints: complaintsWithSignedImages,
|
complaints: complaintsWithSignedImages,
|
||||||
totalCount,
|
nextCursor: hasMore
|
||||||
|
? complaintsToReturn[complaintsToReturn.length - 1].id
|
||||||
|
: undefined,
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,16 +52,7 @@ const HealthTestWrapper: React.FC<HealthTestWrapperProps> = ({ children }) => {
|
||||||
}
|
}
|
||||||
}, [versionFromBackend]);
|
}, [versionFromBackend]);
|
||||||
|
|
||||||
if (isLoading) {
|
if (error) {
|
||||||
return (
|
|
||||||
<View style={tw`flex-1 justify-center items-center bg-gray-50`}>
|
|
||||||
<ActivityIndicator size="large" color={theme.colors.brand500} />
|
|
||||||
<MyText style={tw`text-gray-500 mt-4 font-medium`}>Checking service status...</MyText>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error || data?.status !== "ok") {
|
|
||||||
return (
|
return (
|
||||||
<View style={tw`flex-1 justify-center items-center bg-gray-50 p-6`}>
|
<View style={tw`flex-1 justify-center items-center bg-gray-50 p-6`}>
|
||||||
<View style={tw`w-16 h-16 bg-red-100 rounded-full items-center justify-center mb-4`}>
|
<View style={tw`w-16 h-16 bg-red-100 rounded-full items-center justify-center mb-4`}>
|
||||||
|
|
|
||||||
|
|
@ -63,8 +63,8 @@ const isDevMode = Constants.executionEnvironment !== "standalone";
|
||||||
// const BASE_API_URL = API_URL;
|
// const BASE_API_URL = API_URL;
|
||||||
// const BASE_API_URL = 'http://10.0.2.2:4000';
|
// const BASE_API_URL = 'http://10.0.2.2:4000';
|
||||||
// const BASE_API_URL = 'http://192.168.100.101:4000';
|
// const BASE_API_URL = 'http://192.168.100.101:4000';
|
||||||
// const BASE_API_URL = 'http://192.168.1.3:4000';
|
const BASE_API_URL = 'http://192.168.1.6:4000';
|
||||||
let BASE_API_URL = "https://mf.freshyo.in";
|
// let BASE_API_URL = "https://mf.freshyo.in";
|
||||||
// let BASE_API_URL = 'http://192.168.100.104:4000';
|
// let BASE_API_URL = 'http://192.168.100.104:4000';
|
||||||
// let BASE_API_URL = 'http://192.168.29.176:4000';
|
// let BASE_API_URL = 'http://192.168.29.176:4000';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -200,6 +200,7 @@ interface ConfirmationDialogProps {
|
||||||
message?: string;
|
message?: string;
|
||||||
confirmText?: string;
|
confirmText?: string;
|
||||||
cancelText?: string;
|
cancelText?: string;
|
||||||
|
isLoading?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ConfirmationDialog: React.FC<ConfirmationDialogProps> = (props) => {
|
export const ConfirmationDialog: React.FC<ConfirmationDialogProps> = (props) => {
|
||||||
|
|
@ -211,7 +212,8 @@ export const ConfirmationDialog: React.FC<ConfirmationDialogProps> = (props) =>
|
||||||
title = "Are you sure?",
|
title = "Are you sure?",
|
||||||
message = "Do you really want to proceed with this action?",
|
message = "Do you really want to proceed with this action?",
|
||||||
confirmText = "Confirm",
|
confirmText = "Confirm",
|
||||||
cancelText = "Cancel"
|
cancelText = "Cancel",
|
||||||
|
isLoading = false,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const [comment, setComment] = useState('');
|
const [comment, setComment] = useState('');
|
||||||
|
|
@ -253,8 +255,15 @@ export const ConfirmationDialog: React.FC<ConfirmationDialogProps> = (props) =>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<View style={{ flexDirection: 'row', justifyContent: 'space-between', marginTop: commentNeeded ? 16 : 0 }}>
|
<View style={{ flexDirection: 'row', justifyContent: 'space-between', marginTop: commentNeeded ? 16 : 0 }}>
|
||||||
<MyButton textContent={cancelText} onPress={handleCancel} fillColor="gray1" textColor="white1" />
|
<MyButton textContent={cancelText} onPress={handleCancel} fillColor="gray1" textColor="white1" disabled={isLoading} />
|
||||||
<MyButton textContent={confirmText} style={{ flexShrink: 0 }} onPress={handleConfirm} fillColor="red1" textColor="white1" />
|
<MyButton
|
||||||
|
textContent={isLoading ? "Processing..." : confirmText}
|
||||||
|
style={{ flexShrink: 0 }}
|
||||||
|
onPress={handleConfirm}
|
||||||
|
fillColor="red1"
|
||||||
|
textColor="white1"
|
||||||
|
disabled={isLoading}
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</BottomDialog>
|
</BottomDialog>
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue