This commit is contained in:
shafi54 2026-01-29 01:05:20 +05:30
parent cd5905d40f
commit 46f5fa180c
12 changed files with 89 additions and 22 deletions

View file

@ -19,7 +19,7 @@ import { seed } from 'src/db/seed';
import './src/jobs/jobs-index'; import './src/jobs/jobs-index';
import { startAutomatedJobs } from './src/lib/automatedJobs'; import { startAutomatedJobs } from './src/lib/automatedJobs';
seed() // seed()
initFunc() initFunc()
startAutomatedJobs() startAutomatedJobs()

View file

@ -1,8 +1,8 @@
import { router, publicProcedure, protectedProcedure } from '../trpc-index'; import { router, publicProcedure, 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 { vendorSnippets, deliverySlotInfo, productInfo, orders, orderItems, users } from '../../db/schema'; import { vendorSnippets, deliverySlotInfo, productInfo, orders, orderItems, users, orderStatus } from '../../db/schema';
import { eq, and, inArray, isNotNull, gt, sql, asc } from 'drizzle-orm'; import { eq, and, inArray, isNotNull, gt, sql, asc, ne } from 'drizzle-orm';
import { appUrl } from '../../lib/env-exporter'; import { appUrl } from '../../lib/env-exporter';
const createSnippetSchema = z.object({ const createSnippetSchema = z.object({
@ -225,10 +225,7 @@ export const vendorSnippetsRouter = router({
// Query orders that match the snippet criteria // Query orders that match the snippet criteria
const matchingOrders = await db.query.orders.findMany({ const matchingOrders = await db.query.orders.findMany({
where: and( where: eq(orders.slotId, snippet.slotId!),
eq(orders.slotId, snippet.slotId!),
// We'll filter by products in the application logic
),
with: { with: {
orderItems: { orderItems: {
with: { with: {
@ -239,6 +236,7 @@ export const vendorSnippetsRouter = router({
}, },
}, },
}, },
orderStatus: true,
user: true, user: true,
slot: true, slot: true,
}, },
@ -247,6 +245,8 @@ export const vendorSnippetsRouter = router({
// Filter orders that contain at least one of the snippet's products // Filter orders that contain at least one of the snippet's products
const filteredOrders = matchingOrders.filter(order => { const filteredOrders = matchingOrders.filter(order => {
const status = order.orderStatus;
if (status[0].isCancelled) return false;
const orderProductIds = order.orderItems.map(item => item.productId); const orderProductIds = order.orderItems.map(item => item.productId);
return snippet.productIds.some(productId => orderProductIds.includes(productId)); return snippet.productIds.some(productId => orderProductIds.includes(productId));
}); });
@ -271,11 +271,13 @@ export const vendorSnippetsRouter = router({
is_package_verified: item.is_package_verified, is_package_verified: item.is_package_verified,
})); }));
const orderTotal = products.reduce((sum, p) => sum + p.subtotal, 0);
return { return {
orderId: `ORD${order.readableId.toString().padStart(3, '0')}`, orderId: `ORD${order.readableId.toString().padStart(3, '0')}`,
orderDate: order.createdAt.toISOString(), orderDate: order.createdAt.toISOString(),
customerName: order.user.name, customerName: order.user.name,
totalAmount: order.totalAmount, totalAmount: orderTotal,
slotInfo: order.slot ? { slotInfo: order.slot ? {
time: order.slot.deliveryTime.toISOString(), time: order.slot.deliveryTime.toISOString(),
sequence: order.slot.deliverySequence, sequence: order.slot.deliverySequence,
@ -379,7 +381,7 @@ export const vendorSnippetsRouter = router({
if (!slot) { if (!slot) {
throw new Error("Slot not found"); throw new Error("Slot not found");
} }
// Query orders that match the slot and snippet criteria // Query orders that match the slot and snippet criteria
const matchingOrders = await db.query.orders.findMany({ const matchingOrders = await db.query.orders.findMany({
where: eq(orders.slotId, slotId), where: eq(orders.slotId, slotId),
@ -393,6 +395,7 @@ export const vendorSnippetsRouter = router({
}, },
}, },
}, },
orderStatus: true,
user: true, user: true,
slot: true, slot: true,
}, },
@ -401,6 +404,8 @@ export const vendorSnippetsRouter = router({
// Filter orders that contain at least one of the snippet's products // Filter orders that contain at least one of the snippet's products
const filteredOrders = matchingOrders.filter(order => { const filteredOrders = matchingOrders.filter(order => {
const status = order.orderStatus;
if (status[0]?.isCancelled) return false;
const orderProductIds = order.orderItems.map(item => item.productId); const orderProductIds = order.orderItems.map(item => item.productId);
return snippet.productIds.some(productId => orderProductIds.includes(productId)); return snippet.productIds.some(productId => orderProductIds.includes(productId));
}); });
@ -425,11 +430,13 @@ export const vendorSnippetsRouter = router({
is_package_verified: item.is_package_verified, is_package_verified: item.is_package_verified,
})); }));
const orderTotal = products.reduce((sum, p) => sum + p.subtotal, 0);
return { return {
orderId: `ORD${order.readableId.toString().padStart(3, '0')}`, orderId: `ORD${order.readableId.toString().padStart(3, '0')}`,
orderDate: order.createdAt.toISOString(), orderDate: order.createdAt.toISOString(),
customerName: order.user.name, customerName: order.user.name,
totalAmount: order.totalAmount, totalAmount: orderTotal,
slotInfo: order.slot ? { slotInfo: order.slot ? {
time: order.slot.deliveryTime.toISOString(), time: order.slot.deliveryTime.toISOString(),
sequence: order.slot.deliverySequence, sequence: order.slot.deliverySequence,

View file

@ -712,7 +712,7 @@ export const orderRouter = router({
.input( .input(
z.object({ z.object({
// id: z.string().regex(/^ORD\d+$/, "Invalid order ID format"), // id: z.string().regex(/^ORD\d+$/, "Invalid order ID format"),
id: z.string(), id: z.number(),
reason: z.string().min(1, "Cancellation reason is required"), reason: z.string().min(1, "Cancellation reason is required"),
}) })
) )
@ -723,6 +723,9 @@ export const orderRouter = router({
const readableId = Number(id); const readableId = Number(id);
console.log({id, reason})
// Check if order exists and belongs to user // Check if order exists and belongs to user
const order = await db.query.orders.findFirst({ const order = await db.query.orders.findFirst({
where: eq(orders.id, Number(id)), where: eq(orders.id, Number(id)),

View file

@ -34,6 +34,7 @@ import { useUserDetails } from "@/src/contexts/AuthContext";
import TabLayoutWrapper from "@/components/TabLayoutWrapper"; import TabLayoutWrapper from "@/components/TabLayoutWrapper";
import { useNavigationStore } from "@/src/store/navigationStore"; import { useNavigationStore } from "@/src/store/navigationStore";
import { useGetEssentialConsts } from "@/src/api-hooks/essential-consts.api"; import { useGetEssentialConsts } from "@/src/api-hooks/essential-consts.api";
import NextOrderGlimpse from "@/components/NextOrderGlimpse";
dayjs.extend(relativeTime); dayjs.extend(relativeTime);
// import { StatusBar } from "expo-status-bar"; // import { StatusBar } from "expo-status-bar";
@ -362,6 +363,10 @@ export default function Dashboard() {
setWhiteSectionLayout({ y }); setWhiteSectionLayout({ y });
}} }}
> >
<View style={tw`py-2`}>
<NextOrderGlimpse />
</View>
{/* Section Title */} {/* Section Title */}
<View style={tw`mb-4 pt-2 px-1`}> <View style={tw`mb-4 pt-2 px-1`}>
<MyText style={tw`text-2xl font-extrabold text-gray-900 tracking-tight`}> <MyText style={tw`text-2xl font-extrabold text-gray-900 tracking-tight`}>
@ -491,7 +496,7 @@ export default function Dashboard() {
<MyText <MyText
style={tw`text-[11px] font-bold text-slate-500`} style={tw`text-[11px] font-bold text-slate-500`}
> >
Delivery Slot {dayjs(slot.deliveryTime).format("ddd, MMM DD")}
</MyText> </MyText>
</View> </View>

View file

@ -1,16 +1,28 @@
import React from 'react'; import React from 'react';
import { View, ScrollView } from 'react-native'; import { View, ScrollView } from 'react-native';
import { useRouter } from 'expo-router'; import { useRouter } from 'expo-router';
import { useFocusEffect } from '@react-navigation/native';
import { AppContainer, MyText, tw, MyTouchableOpacity, ProfileImage, colors } from 'common-ui'; import { AppContainer, MyText, tw, MyTouchableOpacity, ProfileImage, colors } from 'common-ui';
import TabLayoutWrapper from '@/components/TabLayoutWrapper'; import TabLayoutWrapper from '@/components/TabLayoutWrapper';
import { LinearGradient } from 'expo-linear-gradient'; import { LinearGradient } from 'expo-linear-gradient';
import { Ionicons } from '@expo/vector-icons'; import { Ionicons } from '@expo/vector-icons';
import NextOrderGlimpse from '@/components/NextOrderGlimpse'; import NextOrderGlimpse from '@/components/NextOrderGlimpse';
import { useAuth } from '@/src/contexts/AuthContext'; import { useAuth } from '@/src/contexts/AuthContext';
import { useNavigationTarget } from 'common-ui/hooks/useNavigationTarget';
export default function Me() { export default function Me() {
const router = useRouter(); const router = useRouter();
const { logout } = useAuth(); const { logout } = useAuth();
const { getNavigationTarget } = useNavigationTarget();
useFocusEffect(() => {
const target = getNavigationTarget();
console.log({target})
if (target) {
router.replace(target as any);
}
});
const menuSections = [ const menuSections = [
{ {

View file

@ -50,6 +50,8 @@ export default function OrderDetails() {
Alert.alert('Success', 'Order cancelled successfully'); Alert.alert('Success', 'Order cancelled successfully');
}, },
onError: (error: any) => { onError: (error: any) => {
console.log({error})
Alert.alert('Error', error.message || 'Failed to cancel order'); Alert.alert('Error', error.message || 'Failed to cancel order');
}, },
}); });
@ -59,7 +61,7 @@ export default function OrderDetails() {
Alert.alert('Error', 'Please enter a reason for cancellation'); Alert.alert('Error', 'Please enter a reason for cancellation');
return; return;
} }
cancelOrderMutation.mutate({ id: order.orderId, reason: cancelReason }); cancelOrderMutation.mutate({ id: order.id, reason: cancelReason });
}; };
useEffect(() => { useEffect(() => {
@ -126,6 +128,12 @@ export default function OrderDetails() {
{/* Simple Header */} {/* Simple Header */}
<View style={tw`bg-white px-6 pt-4 pb-4 border-b border-slate-100 flex-row items-center justify-between`}> <View style={tw`bg-white px-6 pt-4 pb-4 border-b border-slate-100 flex-row items-center justify-between`}>
<View style={tw`flex-row items-center`}> <View style={tw`flex-row items-center`}>
<MyTouchableOpacity
onPress={() => router.back()}
style={tw`mr-3 p-2 -ml-2`}
>
<Ionicons name="chevron-back" size={24} color="#1E293B" />
</MyTouchableOpacity>
<View> <View>
<MyText style={tw`text-slate-900 font-bold text-lg`}>Order #{order.orderId}</MyText> <MyText style={tw`text-slate-900 font-bold text-lg`}>Order #{order.orderId}</MyText>
<MyText style={tw`text-slate-400 text-xs`}>{dayjs(order.orderDate).format("DD MMM, h:mm A")}</MyText> <MyText style={tw`text-slate-400 text-xs`}>{dayjs(order.orderDate).format("DD MMM, h:mm A")}</MyText>
@ -342,10 +350,10 @@ export default function OrderDetails() {
{/* Footer Actions */} {/* Footer Actions */}
<View style={tw`flex-row gap-3`}> <View style={tw`flex-row gap-3`}>
<MyTouchableOpacity <MyTouchableOpacity
onPress={() => router.back()} onPress={() => router.replace('/(drawer)/(tabs)/me')}
style={tw`flex-1 bg-slate-100 py-3.5 rounded-xl items-center`} style={tw`flex-1 bg-slate-100 py-3.5 rounded-xl items-center`}
> >
<MyText style={tw`text-slate-600 font-bold`}>Dismiss</MyText> <MyText style={tw`text-slate-600 font-bold`}>Back</MyText>
</MyTouchableOpacity> </MyTouchableOpacity>
<MyTouchableOpacity <MyTouchableOpacity
onPress={() => setComplaintDialogOpen(true)} onPress={() => setComplaintDialogOpen(true)}

View file

@ -2,6 +2,7 @@ import React from 'react';
import { View, TouchableOpacity, ActivityIndicator } from 'react-native'; import { View, TouchableOpacity, ActivityIndicator } from 'react-native';
import { useRouter } from 'expo-router'; import { useRouter } from 'expo-router';
import { tw, MyText } from 'common-ui'; import { tw, MyText } from 'common-ui';
import { useNavigationTarget } from 'common-ui/hooks/useNavigationTarget';
import { MaterialIcons, Ionicons } from '@expo/vector-icons'; import { MaterialIcons, Ionicons } from '@expo/vector-icons';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { trpc } from '@/src/trpc-client'; import { trpc } from '@/src/trpc-client';
@ -38,6 +39,7 @@ interface Order {
export default function NextOrderGlimpse() { export default function NextOrderGlimpse() {
const router = useRouter(); const router = useRouter();
const { setNavigationTarget } = useNavigationTarget();
const { data: ordersData, isLoading: ordersLoading } = trpc.user.order.getOrders.useQuery({ const { data: ordersData, isLoading: ordersLoading } = trpc.user.order.getOrders.useQuery({
page: 1, page: 1,
@ -97,7 +99,12 @@ export default function NextOrderGlimpse() {
return ( return (
<TouchableOpacity <TouchableOpacity
style={tw`px-6 mb-4`} style={tw`px-6 mb-4`}
onPress={() => router.push(`/(drawer)/(tabs)/me/my-orders/${nextOrder.id}`)} onPress={() => {
console.log('from next press')
setNavigationTarget(`/(drawer)/(tabs)/me/my-orders/${nextOrder.id}`);
router.replace('/(drawer)/(tabs)/me');
}}
> >
<View style={tw`bg-gradient-to-r from-amber-50 to-orange-50 rounded-2xl p-4 border-2 border-amber-300`}> <View style={tw`bg-gradient-to-r from-amber-50 to-orange-50 rounded-2xl p-4 border-2 border-amber-300`}>
<View style={tw`flex-row items-center justify-between mb-3`}> <View style={tw`flex-row items-center justify-between mb-3`}>

View file

@ -18,8 +18,6 @@ interface RedirectState {
export function useAuthenticatedRoute(options: AuthenticatedRouteOptions = {}) { export function useAuthenticatedRoute(options: AuthenticatedRouteOptions = {}) {
const { isAuthenticated, isLoading } = useAuth(); const { isAuthenticated, isLoading } = useAuth();
const router = useRouter(); const router = useRouter();
console.log({ops: options.queryParams})
useFocusEffect(() => { useFocusEffect(() => {
// Don't redirect while auth is loading // Don't redirect while auth is loading

3
package-lock.json generated
View file

@ -24388,7 +24388,8 @@
"react-native-web": "~0.20.0", "react-native-web": "~0.20.0",
"react-native-webview": "13.13.5", "react-native-webview": "13.13.5",
"twrnc": "^4.9.1", "twrnc": "^4.9.1",
"yup": "^1.7.0" "yup": "^1.7.0",
"zustand": "^5.0.10"
} }
}, },
"packages/ui/node_modules/buffer": { "packages/ui/node_modules/buffer": {

View file

@ -0,0 +1,25 @@
import { create } from 'zustand';
interface NavigationTargetState {
navigationTarget: string | null;
setNavigationTarget: (target: string | null) => void;
getNavigationTarget: () => string | null;
}
const useNavigationTargetStore = create<NavigationTargetState>((set, get) => ({
navigationTarget: null,
setNavigationTarget: (target: string | null) => {
set({ navigationTarget: target })
},
getNavigationTarget: () => {
const target = get().navigationTarget;
if (target) {
set({ navigationTarget: null });
}
return target;
},
}));
export function useNavigationTarget() {
return useNavigationTargetStore();
}

View file

@ -64,8 +64,8 @@ const isDevMode = Constants.executionEnvironment !== "standalone";
// 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.14:4000'; // const BASE_API_URL = 'http://192.168.1.14: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.103:4000'; let BASE_API_URL = 'http://192.168.100.103:4000';
// let BASE_API_URL = 'http://192.168.29.219:4000'; // let BASE_API_URL = 'http://192.168.29.219:4000';
// if(isDevMode) { // if(isDevMode) {

View file

@ -57,6 +57,7 @@
"react-native-web": "~0.20.0", "react-native-web": "~0.20.0",
"react-native-webview": "13.13.5", "react-native-webview": "13.13.5",
"twrnc": "^4.9.1", "twrnc": "^4.9.1",
"yup": "^1.7.0" "yup": "^1.7.0",
"zustand": "^5.0.10"
} }
} }