Module Development
Frontend Development
Building React/TypeScript frontend code for AutoCom modules.
Frontend Structure
modules/ShippingDelhivery/frontend/
├── index.ts # Main exports
├── types/
│ └── shipment.ts # TypeScript interfaces
├── hooks/
│ └── use-delhivery.ts # React hooks
└── components/
├── ShipmentTracker.tsx
└── LabelDownload.tsxTypeScript Types
// modules/ShippingDelhivery/frontend/types/shipment.ts
export interface DelhiveryShipment {
id: string;
order_id: string;
awb: string;
status: ShipmentStatus;
weight_kg: number;
dimensions?: {
length: number;
width: number;
height: number;
};
tracking_url: string;
label_url: string | null;
pickup_scheduled_at: string | null;
shipped_at: string | null;
delivered_at: string | null;
created_at: string;
updated_at: string;
}
export type ShipmentStatus =
| 'manifested'
| 'picked_up'
| 'in_transit'
| 'out_for_delivery'
| 'delivered'
| 'rto_initiated'
| 'rto_delivered'
| 'cancelled';
export interface TrackingEvent {
status: string;
location: string;
description: string;
timestamp: string;
}
export interface CreateShipmentPayload {
order_id: string;
weight_kg: number;
dimensions?: {
length: number;
width: number;
height: number;
};
pickup_date?: string;
is_cod?: boolean;
cod_amount?: number;
}React Hooks
// modules/ShippingDelhivery/frontend/hooks/use-delhivery.ts
import { useState, useCallback } from 'react';
import { apiClient } from '@/lib/api-client';
import type {
DelhiveryShipment,
CreateShipmentPayload,
TrackingEvent
} from '../types/shipment';
export function useDelhiveryShipments() {
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const createShipment = useCallback(async (
payload: CreateShipmentPayload
): Promise<DelhiveryShipment> => {
setLoading(true);
setError(null);
try {
const response = await apiClient.post(
'/api/v1/shipping/delhivery/shipments',
payload
);
return response.data.data;
} catch (err: any) {
setError(err.message);
throw err;
} finally {
setLoading(false);
}
}, []);
const trackShipment = useCallback(async (
awb: string
): Promise<TrackingEvent[]> => {
const response = await apiClient.get(
`/api/v1/shipping/delhivery/shipments/${awb}/track`
);
return response.data.data;
}, []);
return {
loading,
error,
createShipment,
trackShipment,
};
}React Components
// modules/ShippingDelhivery/frontend/components/ShipmentTracker.tsx
import { useState, useEffect } from 'react';
import { useDelhiveryShipments } from '../hooks/use-delhivery';
import type { TrackingEvent } from '../types/shipment';
interface ShipmentTrackerProps {
awb: string;
onStatusChange?: (status: string) => void;
}
export function ShipmentTracker({ awb, onStatusChange }: ShipmentTrackerProps) {
const { trackShipment } = useDelhiveryShipments();
const [events, setEvents] = useState<TrackingEvent[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
async function fetchTracking() {
try {
const data = await trackShipment(awb);
setEvents(data);
if (data.length > 0 && onStatusChange) {
onStatusChange(data[0].status);
}
} finally {
setLoading(false);
}
}
fetchTracking();
}, [awb, trackShipment, onStatusChange]);
if (loading) {
return <div className="animate-pulse">Loading tracking...</div>;
}
return (
<div className="space-y-4">
<h3 className="font-medium">Tracking: {awb}</h3>
<div className="space-y-2">
{events.map((event, index) => (
<div
key={index}
className="flex items-start gap-3 p-3 rounded-lg border"
>
<div className="w-2 h-2 mt-2 rounded-full bg-blue-500" />
<div>
<p className="font-medium">{event.status}</p>
<p className="text-sm text-gray-500">{event.location}</p>
<p className="text-xs text-gray-400">{event.timestamp}</p>
</div>
</div>
))}
</div>
</div>
);
}Main Exports (index.ts)
// modules/ShippingDelhivery/frontend/index.ts
// Types
export * from './types/shipment';
// Hooks
export { useDelhiveryShipments } from './hooks/use-delhivery';
// Components
export { ShipmentTracker } from './components/ShipmentTracker';
export { LabelDownload } from './components/LabelDownload';Using Module Exports
Import module exports in your main application:
// In your Next.js app
import {
useDelhiveryShipments,
ShipmentTracker,
type DelhiveryShipment,
} from '@modules/ShippingDelhivery';
function OrderShippingSection({ orderId }: { orderId: string }) {
const { createShipment, loading } = useDelhiveryShipments();
const [shipment, setShipment] = useState<DelhiveryShipment | null>(null);
const handleShip = async () => {
const newShipment = await createShipment({
order_id: orderId,
weight_kg: 0.5,
});
setShipment(newShipment);
};
return (
<div>
{!shipment ? (
<button onClick={handleShip} disabled={loading}>
Create Shipment
</button>
) : (
<ShipmentTracker awb={shipment.awb} />
)}
</div>
);
}Best Practices
Type Everything
Use TypeScript interfaces for all API responses and payloads.
Hooks for Logic
Keep API calls and state management in custom hooks, not components.
Error Handling
Always handle loading and error states in your hooks.
Export Everything
Re-export all public APIs from index.ts for clean imports.