Compare commits

..

No commits in common. "3d7e02396509d957b516a3c145e2d263d8f12272" and "31f011ba8c4645a093fbcad158a1951096746cc0" have entirely different histories.

25 changed files with 72 additions and 190 deletions

File diff suppressed because one or more lines are too long

View file

@ -201,7 +201,9 @@ export default function Layout() {
<Drawer.Screen name="dashboard" options={{ title: "Dashboard" }} /> <Drawer.Screen name="dashboard" options={{ title: "Dashboard" }} />
<Drawer.Screen name="products" options={{ title: "Products" }} /> <Drawer.Screen name="products" options={{ title: "Products" }} />
<Drawer.Screen name="prices-overview" options={{ title: "Prices Overview" }} /> <Drawer.Screen name="prices-overview" options={{ title: "Prices Overview" }} />
<Drawer.Screen name="product-groupings" options={{ title: "Product Groupings" }} /> <Drawer.Screen name="product-groupings" options={{ title: "Product Groupings" }} />
<Drawer.Screen name="create-product-group" options={{ title: "Create Product Group" }} />
<Drawer.Screen name="edit-product-group/[id]" options={{ title: "Edit Product Group" }} />
<Drawer.Screen <Drawer.Screen
@ -211,12 +213,14 @@ export default function Layout() {
<Drawer.Screen name="complaints" options={{ title: "Complaints" }} /> <Drawer.Screen name="complaints" options={{ title: "Complaints" }} />
<Drawer.Screen name="coupons" options={{ title: "Coupons" }} /> <Drawer.Screen name="coupons" options={{ title: "Coupons" }} />
<Drawer.Screen name="slots" options={{ title: "Slots" }} /> <Drawer.Screen name="slots" options={{ title: "Slots" }} />
<Drawer.Screen name="vendor-snippets" options={{ title: "Vendor Snippets" }} /> <Drawer.Screen name="vendor-snippets" options={{ title: "Vendor Snippets" }} />
<Drawer.Screen name="stores" options={{ title: "Stores" }} /> <Drawer.Screen name="delivery-sequences" options={{ title: "Delivery Sequences", headerShown: false }} />
<Drawer.Screen name="stores" options={{ title: "Stores" }} />
<Drawer.Screen name="address-management" options={{ title: "Address Management" }} /> <Drawer.Screen name="address-management" options={{ title: "Address Management" }} />
<Drawer.Screen name="product-tags" options={{ title: "Product Tags" }} /> <Drawer.Screen name="product-tags" options={{ title: "Product Tags" }} />
<Drawer.Screen name="order-details/[id]" options={{ title: "Order Details" }} /> <Drawer.Screen name="order-details/[id]" options={{ title: "Order Details" }} />
<Drawer.Screen name="rebalance-orders" options={{ title: "Rebalance Orders" }} /> <Drawer.Screen name="orders" options={{ title: "Orders" }} />
<Drawer.Screen name="rebalance-orders" options={{ title: "Rebalance Orders" }} />
</Drawer> </Drawer>
); );
} }

View file

@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import { View } from 'react-native'; import { View } from 'react-native';
import { AppContainer } from 'common-ui'; import { AppContainer } from 'common-ui';
import ProductGroupForm from '../../../components/ProductGroupForm'; import ProductGroupForm from '../../components/ProductGroupForm';
import { useRouter } from 'expo-router'; import { useRouter } from 'expo-router';
export default function CreateProductGroup() { export default function CreateProductGroup() {

View file

@ -4,8 +4,8 @@ export default function Layout() {
return ( return (
<Stack screenOptions={{ headerShown: false }}> <Stack screenOptions={{ headerShown: false }}>
<Stack.Screen name="index" options={{ title: 'Dashboard Banners' }} /> <Stack.Screen name="index" options={{ title: 'Dashboard Banners' }} />
<Stack.Screen name="create" options={{ title: 'Create Banner' }} /> <Stack.Screen name="create-banner" options={{ title: 'Create Banner' }} />
<Stack.Screen name="edit/[id]" options={{ title: 'Edit Banner' }} /> <Stack.Screen name="edit-banner" options={{ title: 'Edit Banner' }} />
</Stack> </Stack>
); );
} }

View file

@ -0,0 +1,9 @@
import { Stack } from 'expo-router';
export default function Layout() {
return (
<Stack screenOptions={{ headerShown: false }}>
<Stack.Screen name="index" options={{ title: 'Create Banner' }} />
</Stack>
);
}

View file

@ -5,7 +5,7 @@ import MaterialIcons from '@expo/vector-icons/MaterialIcons';
import { useRouter } from 'expo-router'; import { useRouter } from 'expo-router';
import { FormikHelpers } from 'formik'; import { FormikHelpers } from 'formik';
import BannerForm, { BannerFormData } from '@/components/BannerForm'; import BannerForm, { BannerFormData } from '@/components/BannerForm';
import { trpc } from '@/src/trpc-client'; import { trpc } from '../../../../src/trpc-client';
export default function CreateBanner() { export default function CreateBanner() {
const router = useRouter(); const router = useRouter();

View file

@ -5,7 +5,7 @@ import MaterialIcons from '@expo/vector-icons/MaterialIcons';
import { useRouter, useLocalSearchParams } from 'expo-router'; import { useRouter, useLocalSearchParams } from 'expo-router';
import { FormikHelpers } from 'formik'; import { FormikHelpers } from 'formik';
import BannerForm, { BannerFormData } from '@/components/BannerForm'; import BannerForm, { BannerFormData } from '@/components/BannerForm';
import { trpc } from '@/src/trpc-client'; import { trpc } from '../../../../src/trpc-client';
interface Banner { interface Banner {
id: number; id: number;

View file

@ -0,0 +1,9 @@
import { Stack } from 'expo-router';
export default function Layout() {
return (
<Stack screenOptions={{ headerShown: false }}>
<Stack.Screen name="[id]" options={{ title: 'Edit Banner' }} />
</Stack>
);
}

View file

@ -180,7 +180,7 @@ export default function DashboardBanners() {
}; };
const handleEdit = (banner: Banner) => { const handleEdit = (banner: Banner) => {
router.push(`/dashboard-banners/edit/${banner.id}` as any); router.push(`/dashboard-banners/edit-banner/${banner.id}` as any);
}; };
const handleDelete = (id: number) => { const handleDelete = (id: number) => {
@ -207,7 +207,7 @@ export default function DashboardBanners() {
}; };
const handleCreate = () => { const handleCreate = () => {
router.push('/dashboard-banners/create' as any); router.push('/(drawer)/dashboard-banners/create-banner' as any);
}; };
if (isLoading) { if (isLoading) {

View file

@ -6,7 +6,6 @@ import { MyText, tw } from 'common-ui';
import { LinearGradient } from 'expo-linear-gradient'; import { LinearGradient } from 'expo-linear-gradient';
import { theme } from 'common-ui/src/theme'; import { theme } from 'common-ui/src/theme';
import { trpc } from '@/src/trpc-client'; import { trpc } from '@/src/trpc-client';
import { useNavigationTarget } from 'common-ui/hooks/useNavigationTarget';
interface MenuItem { interface MenuItem {
title: string; title: string;
@ -17,7 +16,6 @@ interface MenuItem {
iconColor?: string; iconColor?: string;
iconBg?: string; iconBg?: string;
badgeCount?: number; badgeCount?: number;
onPress?: () => void;
} }
interface MenuItemComponentProps { interface MenuItemComponentProps {
@ -29,7 +27,8 @@ const MenuItemComponent: React.FC<MenuItemComponentProps> = ({ item, router }) =
return ( return (
<Pressable <Pressable
onPress={() => item.onPress ? item.onPress() : router.push(item.route as any)} key={item.route}
onPress={() => router.push(item.route as any)}
style={({ pressed }) => [ style={({ pressed }) => [
tw`flex-row items-center p-4 bg-white border border-gray-100 rounded-xl mb-3 shadow-sm`, tw`flex-row items-center p-4 bg-white border border-gray-100 rounded-xl mb-3 shadow-sm`,
pressed && tw`bg-gray-50`, pressed && tw`bg-gray-50`,
@ -56,41 +55,28 @@ const MenuItemComponent: React.FC<MenuItemComponentProps> = ({ item, router }) =
export default function Dashboard() { export default function Dashboard() {
const router = useRouter(); const router = useRouter();
const { setNavigationTarget } = useNavigationTarget();
const { data: essentialsData } = trpc.admin.user.getEssentials.useQuery(); const { data: essentialsData } = trpc.admin.user.getEssentials.useQuery();
const handleManageOrdersPress = () => {
setNavigationTarget('/manage-orders/orders');
router.push('/(drawer)/manage-orders');
};
const handleDeliverySequencesPress = () => {
setNavigationTarget('/manage-orders/delivery-sequences');
router.push('/(drawer)/manage-orders');
};
const menuItems: MenuItem[] = [ const menuItems: MenuItem[] = [
{ {
title: 'Manage Orders', title: 'Manage Orders',
icon: 'shopping-bag', icon: 'shopping-bag',
description: 'View and manage customer orders', description: 'View and manage customer orders',
route: '/(drawer)/manage-orders', route: '/(drawer)/orders',
category: 'orders', category: 'orders',
iconColor: '#10B981', iconColor: '#10B981',
iconBg: '#D1FAE5', iconBg: '#D1FAE5',
onPress: handleManageOrdersPress,
}, },
{ {
title: 'Delivery Sequences', title: 'Delivery Sequences',
icon: 'alt-route', icon: 'alt-route',
description: 'Plan and optimize delivery routes', description: 'Plan and optimize delivery routes',
route: '/manage-orders/delivery-sequences', route: '/(drawer)/delivery-sequences',
category: 'orders', category: 'orders',
iconColor: '#8B5CF6', iconColor: '#8B5CF6',
iconBg: '#EDE9FE', iconBg: '#EDE9FE',
onPress: handleDeliverySequencesPress,
}, },
{ {
title: 'Delivery Slots', title: 'Delivery Slots',
@ -225,8 +211,8 @@ export default function Dashboard() {
<View style={tw`flex-row flex-wrap gap-3`}> <View style={tw`flex-row flex-wrap gap-3`}>
{quickActions.map((item) => ( {quickActions.map((item) => (
<Pressable <Pressable
key={`quick-${item.route}`} key={item.route}
onPress={() => item.onPress ? item.onPress() : router.push(item.route as any)} onPress={() => router.push(item.route as any)}
style={({ pressed }) => [ style={({ pressed }) => [
tw`bg-white rounded-xl p-3 shadow-sm border border-gray-100 items-center`, tw`bg-white rounded-xl p-3 shadow-sm border border-gray-100 items-center`,
{ width: 'calc(25% - 9px)' }, { width: 'calc(25% - 9px)' },
@ -263,7 +249,7 @@ export default function Dashboard() {
</View> </View>
<MyText style={tw`text-gray-700 font-bold text-base`}>{category.title}</MyText> <MyText style={tw`text-gray-700 font-bold text-base`}>{category.title}</MyText>
</View> </View>
{categoryItems.map(item => <MenuItemComponent key={`menu-${item.route}`} item={item} router={router} />)} {categoryItems.map(item => <MenuItemComponent key={item.route} item={item} router={router} />)}
</View> </View>
); );
})} })}

View file

@ -2,8 +2,8 @@ import { Stack } from 'expo-router';
export default function Layout() { export default function Layout() {
return ( return (
<Stack> <Stack screenOptions={{ headerShown: false }}>
<Stack.Screen name="index" options={{ title: 'Delivery Sequences', headerShown: false }} /> <Stack.Screen name="index" options={{ title: 'Delivery Sequences' }} />
</Stack> </Stack>
); );
} }

View file

@ -302,7 +302,7 @@ export default function DeliverySequences() {
// Auto-select first slot if no slotId provided // Auto-select first slot if no slotId provided
useEffect(() => { useEffect(() => {
if (!slotId && slotsData?.slots && slotsData.slots.length > 0) { if (!slotId && slotsData?.slots && slotsData.slots.length > 0) {
router.replace(`/manage-orders/delivery-sequences?slotId=${slotsData.slots[0].id}`); router.replace(`/delivery-sequences?slotId=${slotsData.slots[0].id}`);
} }
}, [slotId, slotsData, router]); }, [slotId, slotsData, router]);
@ -505,7 +505,7 @@ export default function DeliverySequences() {
value={selectedSlotId || ""} value={selectedSlotId || ""}
onValueChange={(val) => { onValueChange={(val) => {
if (val) { if (val) {
router.replace(`/manage-orders/delivery-sequences?slotId=${val}`); router.replace(`/delivery-sequences?slotId=${val}`);
} }
}} }}
placeholder="Select slot" placeholder="Select slot"

View file

@ -1,9 +1,9 @@
import React from 'react'; import React from 'react';
import { View } from 'react-native'; import { View } from 'react-native';
import { AppContainer, MyText } from 'common-ui'; import { AppContainer, MyText } from 'common-ui';
import ProductGroupForm from '../../../../components/ProductGroupForm'; import ProductGroupForm from '../../../components/ProductGroupForm';
import { useRouter, useLocalSearchParams } from 'expo-router'; import { useRouter, useLocalSearchParams } from 'expo-router';
import { trpc } from '@/src/trpc-client'; import { trpc } from '../../../src/trpc-client';
export default function EditProductGroup() { export default function EditProductGroup() {
const router = useRouter(); const router = useRouter();

View file

@ -4,8 +4,6 @@ export default function Layout() {
return ( return (
<Stack screenOptions={{ headerShown: false }}> <Stack screenOptions={{ headerShown: false }}>
<Stack.Screen name="index" options={{ title: 'Manage Orders' }} /> <Stack.Screen name="index" options={{ title: 'Manage Orders' }} />
<Stack.Screen name="delivery-sequences" options={{ title: 'Delivery Sequences' }} />
<Stack.Screen name="orders" options={{ title: 'Orders' }} />
</Stack> </Stack>
); );
} }

View file

@ -1,28 +1,16 @@
import { View, TouchableOpacity, Alert } from 'react-native'; import { View, TouchableOpacity, Alert } from 'react-native';
import { MyText, BottomDropdown, tw, MyFlatList, useMarkDataFetchers } from 'common-ui'; import { MyText, BottomDropdown, tw, MyFlatList, useMarkDataFetchers } from 'common-ui';
import { useRouter } from 'expo-router'; import { useRouter } from 'expo-router';
import { useFocusEffect } from '@react-navigation/native';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { useState, useCallback } from 'react'; import { useState } from 'react';
import MaterialIcons from '@expo/vector-icons/MaterialIcons'; import MaterialIcons from '@expo/vector-icons/MaterialIcons';
import { trpc } from '@/src/trpc-client'; import { trpc } from '@/src/trpc-client';
import { useNavigationTarget } from 'common-ui/hooks/useNavigationTarget';
export default function ManageOrders() { export default function ManageOrders() {
const router = useRouter(); const router = useRouter();
const { getNavigationTarget } = useNavigationTarget();
const [selectedSlotId, setSelectedSlotId] = useState<string | null>(null); const [selectedSlotId, setSelectedSlotId] = useState<string | null>(null);
const { data: slotsData, refetch } = trpc.admin.slots.getAll.useQuery(); const { data: slotsData, refetch } = trpc.admin.slots.getAll.useQuery();
useFocusEffect(
useCallback(() => {
const target = getNavigationTarget();
if (target) {
router.replace(target as any);
}
}, [router, getNavigationTarget])
);
useMarkDataFetchers(() => { useMarkDataFetchers(() => {
refetch(); refetch();
}); });
@ -46,7 +34,7 @@ export default function ManageOrders() {
Alert.alert('Flash Deliveries', 'Flash deliveries do not have delivery sequences. Use the Orders menu to manage flash deliveries.'); Alert.alert('Flash Deliveries', 'Flash deliveries do not have delivery sequences. Use the Orders menu to manage flash deliveries.');
return; return;
} }
router.push(`/manage-orders/delivery-sequences?slotId=${selectedSlotId}`); router.push(`/(drawer)/delivery-sequences?slotId=${selectedSlotId}`);
}, },
}, },
{ {
@ -55,9 +43,9 @@ export default function ManageOrders() {
color: 'bg-cyan-500', color: 'bg-cyan-500',
onPress: () => { onPress: () => {
if (selectedSlotId === 'flash') { if (selectedSlotId === 'flash') {
router.push('/manage-orders/orders?filter=flash'); router.push('/(drawer)/orders?filter=flash');
} else { } else {
router.push('/manage-orders/orders'); router.push('/(drawer)/orders');
} }
}, },
}, },

View file

@ -1,9 +0,0 @@
import { Stack } from 'expo-router';
export default function Layout() {
return (
<Stack>
<Stack.Screen name="index" options={{ title: 'Orders', headerShown: false }} />
</Stack>
);
}

View file

@ -0,0 +1,9 @@
import { Stack } from 'expo-router';
export default function Layout() {
return (
<Stack screenOptions={{ headerShown: false }}>
<Stack.Screen name="index" options={{ title: 'Orders' }} />
</Stack>
);
}

View file

@ -1,7 +1,7 @@
import React, { useState , useEffect } from 'react'; import React, { useState , useEffect } from 'react';
import { View, TouchableOpacity, Alert, TextInput, ActivityIndicator, Linking } from 'react-native'; import { View, TouchableOpacity, Alert, TextInput, ActivityIndicator, Linking } from 'react-native';
import { AppContainer, MyText, tw, MyFlatList, BottomDialog, BottomDropdown, Checkbox, theme, MyTextInput } from 'common-ui'; import { AppContainer, MyText, tw, MyFlatList, BottomDialog, BottomDropdown, Checkbox, theme, MyTextInput } from 'common-ui';
import { trpc } from '@/src/trpc-client'; import { trpc } from '../../../src/trpc-client';
import { useRouter, useLocalSearchParams } from 'expo-router'; import { useRouter, useLocalSearchParams } from 'expo-router';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import MaterialIcons from '@expo/vector-icons/MaterialIcons'; import MaterialIcons from '@expo/vector-icons/MaterialIcons';

View file

@ -4,8 +4,6 @@ export default function Layout() {
return ( return (
<Stack screenOptions={{ headerShown: false }}> <Stack screenOptions={{ headerShown: false }}>
<Stack.Screen name="index" options={{ title: 'Product Groupings' }} /> <Stack.Screen name="index" options={{ title: 'Product Groupings' }} />
<Stack.Screen name="create" options={{ title: 'Create Product Group' }} />
<Stack.Screen name="edit/[id]" options={{ title: 'Edit Product Group' }} />
</Stack> </Stack>
); );
} }

View file

@ -143,11 +143,11 @@ export default function ProductGroupings() {
}); });
const handleCreate = () => { const handleCreate = () => {
router.push("/product-groupings/create"); router.push("/(drawer)/create-product-group");
}; };
const handleEdit = (group: ProductGroup) => { const handleEdit = (group: ProductGroup) => {
router.push(`/product-groupings/edit/${group.id}`); router.push(`/(drawer)/edit-product-group/${group.id}`);
}; };
const handleDelete = (id: number) => { const handleDelete = (id: number) => {

View file

@ -198,7 +198,7 @@ export default function SlotDetails() {
{/* FAB for Edit Slot */} {/* FAB for Edit Slot */}
<MyTouchableOpacity <MyTouchableOpacity
onPress={() => router.push(`/slots/edit/${slot.id}` as any)} onPress={() => router.push(`/edit-slot/${slot.id}` as any)}
activeOpacity={0.95} activeOpacity={0.95}
style={{ position: 'absolute', bottom: 32, right: 24, zIndex: 100 }} style={{ position: 'absolute', bottom: 32, right: 24, zIndex: 100 }}
> >

View file

@ -1,6 +1,6 @@
import './notif-job'; import './notif-job';
import { initializeAllStores } from '../stores/store-initializer'; import { initializeAllStores } from '../stores/store-initializer';
import { startOrderHandler, startCancellationHandler, publishOrder } from './post-order-handler'; import { startOrderHandler, publishOrder } from './post-order-handler';
import { deleteOrders } from './delete-orders'; import { deleteOrders } from './delete-orders';
/** /**
@ -9,7 +9,6 @@ import { deleteOrders } from './delete-orders';
* - Role Manager (fetches and caches all roles) * - Role Manager (fetches and caches all roles)
* - Const Store (syncs constants from DB to Redis) * - Const Store (syncs constants from DB to Redis)
* - Post Order Handler (Redis Pub/Sub subscriber) * - Post Order Handler (Redis Pub/Sub subscriber)
* - Cancellation Handler (Redis Pub/Sub subscriber for order cancellations)
* - Other services can be added here in the future * - Other services can be added here in the future
*/ */
export const initFunc = async (): Promise<void> => { export const initFunc = async (): Promise<void> => {
@ -19,7 +18,6 @@ export const initFunc = async (): Promise<void> => {
await Promise.all([ await Promise.all([
initializeAllStores(), initializeAllStores(),
startOrderHandler(), startOrderHandler(),
startCancellationHandler(),
]); ]);
console.log('Application initialization completed successfully'); console.log('Application initialization completed successfully');

View file

@ -1,23 +1,15 @@
import { db } from '../db/db_index'; import { db } from '../db/db_index';
import { orders, orderStatus } from '../db/schema'; import { orders } from '../db/schema';
import redisClient from './redis-client'; import redisClient from './redis-client';
import { sendTelegramMessage } from './telegram-service'; import { sendTelegramMessage } from './telegram-service';
import { inArray, eq } from 'drizzle-orm'; import { inArray } from 'drizzle-orm';
const ORDER_CHANNEL = 'orders:placed'; const ORDER_CHANNEL = 'orders:placed';
const CANCELLED_CHANNEL = 'orders:cancelled';
interface OrderIdMessage { interface OrderIdMessage {
orderIds: number[]; orderIds: number[];
} }
interface CancellationMessage {
orderId: number;
cancelledBy: 'user' | 'admin';
reason: string;
cancelledAt: string;
}
const formatDateTime = (dateStr: string | null | undefined): string => { const formatDateTime = (dateStr: string | null | undefined): string => {
if (!dateStr) return 'N/A'; if (!dateStr) return 'N/A';
return new Date(dateStr).toLocaleString('en-IN', { return new Date(dateStr).toLocaleString('en-IN', {
@ -63,28 +55,6 @@ const formatOrderMessageWithFullData = (ordersData: any[]): string => {
return message; return message;
}; };
const formatCancellationMessage = (orderData: any, cancellationData: CancellationMessage): string => {
const message = `❌ <b>Order Cancelled</b>
<b>Order #${orderData.id}</b>
👤 <b>Name:</b> ${orderData.address?.name || 'N/A'}
📞 <b>Phone:</b> ${orderData.address?.phone || 'N/A'}
📦 <b>Items:</b>
${orderData.orderItems?.map((item: any) => `${item.product?.name || 'Unknown'} x${item.quantity}`).join('\n') || ' N/A'}
💰 <b>Total:</b> ${orderData.totalAmount}
💳 <b>Refund:</b> ${orderData.refundStatus === 'na' ? 'N/A (COD)' : orderData.refundStatus || 'Pending'}
<b>Reason:</b> ${cancellationData.reason}
👤 <b>Cancelled by:</b> ${cancellationData.cancelledBy === 'admin' ? 'Admin' : 'User'}
<b>Time:</b> ${formatDateTime(cancellationData.cancelledAt)}
`;
return message;
};
/** /**
* Start the post order handler * Start the post order handler
* Subscribes to the orders:placed channel and sends to Telegram * Subscribes to the orders:placed channel and sends to Telegram
@ -134,56 +104,6 @@ export const stopOrderHandler = async (): Promise<void> => {
} }
}; };
export const startCancellationHandler = async (): Promise<void> => {
try {
console.log('Starting cancellation handler...');
await redisClient.subscribe(CANCELLED_CHANNEL, async (message: string) => {
try {
const cancellationData: CancellationMessage = JSON.parse(message);
console.log('Order cancellation received, sending to Telegram...');
const orderData = await db.query.orders.findFirst({
where: eq(orders.id, cancellationData.orderId),
with: {
address: true,
orderItems: { with: { product: true } },
refunds: true,
},
});
if (!orderData) {
console.error('Order not found for cancellation:', cancellationData.orderId);
await sendTelegramMessage(`⚠️ Order ${cancellationData.orderId} was cancelled but could not be found in database`);
return;
}
const refundStatus = orderData.refunds?.[0]?.refundStatus || 'pending';
const telegramMessage = formatCancellationMessage({ ...orderData, refundStatus }, cancellationData);
await sendTelegramMessage(telegramMessage);
} catch (error) {
console.error('Failed to process cancellation message:', error);
await sendTelegramMessage(`⚠️ Error processing cancellation: ${message}`);
}
});
console.log('Cancellation handler started successfully');
} catch (error) {
console.error('Failed to start cancellation handler:', error);
throw error;
}
};
export const stopCancellationHandler = async (): Promise<void> => {
try {
await redisClient.unsubscribe(CANCELLED_CHANNEL);
console.log('Cancellation handler stopped');
} catch (error) {
console.error('Error stopping cancellation handler:', error);
}
};
export const publishOrder = async (orderDetails: OrderIdMessage): Promise<boolean> => { export const publishOrder = async (orderDetails: OrderIdMessage): Promise<boolean> => {
try { try {
const message = JSON.stringify(orderDetails); const message = JSON.stringify(orderDetails);
@ -207,24 +127,3 @@ export const publishFormattedOrder = async (
return false; return false;
} }
}; };
export const publishCancellation = async (
orderId: number,
cancelledBy: 'user' | 'admin',
reason: string
): Promise<boolean> => {
try {
const message: CancellationMessage = {
orderId,
cancelledBy,
reason,
cancelledAt: new Date().toISOString(),
};
await redisClient.publish(CANCELLED_CHANNEL, JSON.stringify(message));
console.log('Cancellation published to Redis:', orderId);
return true;
} catch (error) {
console.error('Failed to publish cancellation:', error);
return false;
}
};

View file

@ -19,7 +19,6 @@ import {
sendOrderPackagedNotification, sendOrderPackagedNotification,
sendOrderDeliveredNotification, sendOrderDeliveredNotification,
} from "../../lib/notif-job"; } from "../../lib/notif-job";
import { publishCancellation } from "../../lib/post-order-handler";
const updateOrderNotesSchema = z.object({ const updateOrderNotesSchema = z.object({
orderId: z.number(), orderId: z.number(),
@ -956,9 +955,6 @@ export const orderRouter = router({
return { orderId: order.id, userId: order.userId }; return { orderId: order.id, userId: order.userId };
}); });
// Publish to Redis for Telegram notification
await publishCancellation(result.orderId, 'admin', reason);
return { success: true, message: "Order cancelled successfully" }; return { success: true, message: "Order cancelled successfully" };
}), }),
}); });

View file

@ -25,7 +25,7 @@ import {
import { RazorpayPaymentService } from "../../lib/payments-utils"; import { RazorpayPaymentService } from "../../lib/payments-utils";
import { getNextDeliveryDate } from "../common-apis/common"; import { getNextDeliveryDate } from "../common-apis/common";
import { CONST_KEYS, getConstant, getConstants } from "../../lib/const-store"; import { CONST_KEYS, getConstant, getConstants } from "../../lib/const-store";
import { publishFormattedOrder, publishCancellation } from "../../lib/post-order-handler"; import { publishFormattedOrder } from "../../lib/post-order-handler";
const validateAndGetCoupon = async ( const validateAndGetCoupon = async (
@ -785,9 +785,6 @@ export const orderRouter = router({
result.orderId.toString() result.orderId.toString()
); );
// Publish to Redis for Telegram notification
await publishCancellation(result.orderId, 'user', reason);
return { success: true, message: "Order cancelled successfully" }; return { success: true, message: "Order cancelled successfully" };
} catch (e) { } catch (e) {
console.log(e); console.log(e);