Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions backend/app/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
from rest_framework_simplejwt.views import TokenRefreshView
from rest_framework.urlpatterns import format_suffix_patterns # ✅ For better API format handling
from .views import (
CustomAuthToken, logout_view, get_employees, get_retailers,get_counts,
get_orders,get_users,get_employee_orders,get_employee_shipments,update_shipment_status,get_logged_in_user,allocate_orders, get_trucks, get_shipments,get_stock_data,category_stock_data,store_qr_code
CustomAuthToken, get_employee_id, logout_view, get_employees, get_retailers,get_counts,
get_orders,get_users,get_employee_orders,get_employee_shipments, recent_actions,update_shipment_status,get_logged_in_user,allocate_orders, get_trucks, get_shipments,get_stock_data,category_stock_data,store_qr_code
)

urlpatterns = [
Expand All @@ -29,7 +29,10 @@
path('user_detail/', get_logged_in_user, name='get_logged_in_user'),
path('employee_shipments/', get_employee_shipments, name='employee_shipments'),
path('update_shipment_status/', update_shipment_status, name='update-shipment-status'),
path('employee_orders/', get_employee_orders, name='get_employee_orders')
path('employee_orders/', get_employee_orders, name='get_employee_orders'),
path('employee_id/', get_employee_id, name='get_employee_id'),

path('recent_actions/', recent_actions, name='recent_actions')
]

# ✅ Support API requests with format suffixes (e.g., /orders.json, /orders.xml)
Expand Down
37 changes: 36 additions & 1 deletion backend/app/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from django.contrib.auth.models import User
from django.http import JsonResponse
from .permissions import IsEmployeeUser
from django.contrib.admin.models import LogEntry;

# ✅ Custom Pagination Class
class StandardPagination(PageNumberPagination):
Expand Down Expand Up @@ -363,4 +364,38 @@ def get_employee_orders(request):
return Response(serializer.data)

def redirect_view(request):
return redirect('/admin/')
return redirect('/admin/')


@api_view(['GET'])
@permission_classes([IsAuthenticated,IsEmployeeUser])
def get_employee_id(request):
user = request.user

try:
employee = Employee.objects.get(user=user) # Get employee linked to logged-in user
return Response({"employee_id": employee.employee_id}) # ✅ Use employee_id instead of id
except Employee.DoesNotExist:
return Response({"error": "Employee not found"}, status=404)


@api_view(['GET'])
@permission_classes([IsAuthenticated, IsAdminUser])
def recent_actions(request):
# Fetch the last 10 actions performed in the admin panel
actions = LogEntry.objects.select_related('content_type', 'user').order_by('-action_time')[:10]

# Prepare JSON response
recent_actions_list = [
{
'time': action.action_time,
'user': action.user.username,
'content_type': action.content_type.model,
'object_id': action.object_id,
'object_repr': action.object_repr,
'action_flag': action.get_action_flag_display(),
}
for action in actions
]

return Response({'recent_actions': recent_actions_list})
7 changes: 4 additions & 3 deletions backend/main/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,10 @@
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'smartchain_db',
'USER': 'smartchain',
'PASSWORD': 'venkat*2005',
'NAME': 'sony',
'USER': 'sonyin',
'PASSWORD': 'steamers',

'HOST': 'localhost', # If running PostgreSQL locally
'PORT': '5432', # Default PostgreSQL port
}
Expand Down
128 changes: 89 additions & 39 deletions frontend/app/employee/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@

import React, { useEffect, useState, useMemo, useCallback } from "react";
import { OrdersTable } from "@/components/employee/OrdersTable";
import { UndeliverableOrders } from "@/components/employee/UndeliverableOrders";
import { OrderDetails } from "@/components/employee/OrderDetails";
import { DeliveryStatus } from "@/components/employee/DeliveryStatus";
import { CancelOrderDialog } from "@/components/employee/CancelOrderDialog";
import { DeliveryOrder, UndeliverableOrder } from "@/components/employee/types";
import { DeliveryOrder } from "@/components/employee/types";

interface PageProps {
params: {
id: string;
};
}

const API_URL = "http://127.0.0.1:8000/api";
const API_URL = process.env.REACT_APP_API_URL || "http://127.0.0.1:8000/api";

const getRefreshToken = () => localStorage.getItem("refresh_token");

Expand Down Expand Up @@ -53,7 +53,9 @@ export default function EmployeePage({ params }: PageProps) {
const [selectedOrderId, setSelectedOrderId] = useState<string | null>(null);
const [selectedReason, setSelectedReason] = useState("");
const [orders, setOrders] = useState<DeliveryOrder[]>([]);
const [undeliverableOrders, setUndeliverableOrders] = useState<UndeliverableOrder[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const [employeeId, setEmployeeId] = useState<string | null>(null);

const getAuthToken = useCallback(async () => {
let token = localStorage.getItem("access_token");
Expand All @@ -65,7 +67,8 @@ export default function EmployeePage({ params }: PageProps) {

const fetchWithAuth = async (url: string, options: RequestInit = {}) => {
let token = await getAuthToken();
if (!token) throw new Error("Authentication token not found. Please log in again.");
if (!token)
throw new Error("Authentication token not found. Please log in again.");

const response = await fetch(url, {
...options,
Expand All @@ -78,7 +81,8 @@ export default function EmployeePage({ params }: PageProps) {

if (response.status === 401) {
token = await refreshAccessToken();
if (!token) throw new Error("Authentication token not found. Please log in again.");
if (!token)
throw new Error("Authentication token not found. Please log in again.");

return fetch(url, {
...options,
Expand All @@ -94,34 +98,61 @@ export default function EmployeePage({ params }: PageProps) {
};

useEffect(() => {
async function fetchEmployeeId() {
try {
const response = await fetchWithAuth(`${API_URL}/employee_id/`);
if (!response.ok) {
throw new Error("Failed to fetch employee ID");
}
const data = await response.json();
setEmployeeId(data.employee_id);
} catch (error) {
setError(
error instanceof Error ? error.message : "Unknown error occurred"
);
}
}

fetchEmployeeId();
setMounted(true);
}, []);

useEffect(() => {
async function fetchShipments() {
if (!employeeId) return;

try {
const response = await fetchWithAuth(`${API_URL}/employee_shipments?employeeId=${params.id}`);
setLoading(true);
setError(null);
const response = await fetchWithAuth(
`${API_URL}/employee_shipments?employeeId=${employeeId}`
);
const data = await response.json();

const mappedOrders: DeliveryOrder[] = data.map((shipment: any) => ({
orderId: `SHIP-${shipment.shipment_id}`,
orderName: `Order-${shipment.order}`,
phoneNumber: "N/A", // No phone number in API, set default or fetch separately
address: "N/A", // No address in API, set default or fetch separately
phoneNumber: "N/A",
address: "N/A",
isDelivered: shipment.status === "delivered",
items: [`Order-${shipment.order}`], // Assuming order details are not available in shipment data
items: [`Order-${shipment.order}`],
isCancelled: shipment.status === "cancelled",
cancellationReason: shipment.status === "cancelled" ? "Unknown" : undefined,
cancellationReason:
shipment.status === "cancelled" ? "Unknown" : undefined,
}));

setOrders(mappedOrders);
} catch (error) {
console.error("Failed to fetch shipments:", error);
setError(
error instanceof Error ? error.message : "Unknown error occurred"
);
} finally {
setLoading(false);
}
}

fetchShipments();
}, [params.id]);
}, [employeeId]);

const handleCancelClick = (orderId: string) => {
setSelectedOrderId(orderId);
Expand All @@ -130,10 +161,14 @@ export default function EmployeePage({ params }: PageProps) {

const handleCancelOrder = () => {
if (selectedOrderId && selectedReason) {
setOrders(prevOrders =>
prevOrders.map(order =>
setOrders((prevOrders) =>
prevOrders.map((order) =>
order.orderId === selectedOrderId
? { ...order, isCancelled: true, cancellationReason: selectedReason }
? {
...order,
isCancelled: true,
cancellationReason: selectedReason,
}
: order
)
);
Expand All @@ -145,49 +180,60 @@ export default function EmployeePage({ params }: PageProps) {

const handleUpdateStatus = async (shipmentId: number) => {
try {
const response = await fetchWithAuth(`${API_URL}/update_shipment_status/`, {
method: "POST",
body: JSON.stringify({
shipment_id: shipmentId,
status: "delivered",
}),
});
const response = await fetchWithAuth(
`${API_URL}/update_shipment_status/`,
{
method: "POST",
body: JSON.stringify({
shipment_id: shipmentId,
status: "delivered",
}),
}
);

if (!response.ok) {
throw new Error(`Failed to update status: ${response.statusText}`);
}

// Update the local state to reflect the change
setOrders(prevOrders =>
prevOrders.map(order =>
setOrders((prevOrders) =>
prevOrders.map((order) =>
order.orderId === `SHIP-${shipmentId}`
? { ...order, isDelivered: true }
: order
)
);
} catch (error) {
console.error("Failed to update shipment status:", error);
setError(
error instanceof Error ? error.message : "Unknown error occurred"
);
}
};

const calculatePieChartData = useMemo(() => {
const deliveredCount = orders.filter(order => order.isDelivered && !order.isCancelled).length;
const notDeliveredCount = orders.filter(order => !order.isDelivered && !order.isCancelled).length;
const cancelledCount = orders.filter(order => order.isCancelled).length;
const undeliverableCount = undeliverableOrders.length;
const deliveredCount = orders.filter(
(order) => order.isDelivered && !order.isCancelled
).length;
const notDeliveredCount = orders.filter(
(order) => !order.isDelivered && !order.isCancelled
).length;
const cancelledCount = orders.filter((order) => order.isCancelled).length;

return [
{ name: "Delivered", value: deliveredCount, color: "#22c55e" },
{ name: "Pending", value: notDeliveredCount, color: "#3b82f6" },
{ name: "Cancelled", value: cancelledCount, color: "#eab308" },
{ name: "Undeliverable", value: undeliverableCount, color: "#94a3b8" }
];
}, [orders, undeliverableOrders]);
}, [orders]);

return (
<div className="container mx-auto p-6 space-y-6">
<h1 className="text-2xl font-bold mb-6">Employee Dashboard - ID: {params.id}</h1>

<h1 className="text-2xl font-bold mb-6">
Employee Dashboard - ID : {employeeId || "Loading..."}
</h1>

{error && <p className="text-red-500 p-4">Error: {error}</p>}
{loading && <p className="text-slate-300 p-4">Loading shipments...</p>}

<CancelOrderDialog
open={dialogOpen}
onOpenChange={setDialogOpen}
Expand All @@ -196,17 +242,21 @@ export default function EmployeePage({ params }: PageProps) {
onConfirm={handleCancelOrder}
/>

<OrdersTable orders={orders} onCancelClick={handleCancelClick} onUpdateStatus={handleUpdateStatus} />
<OrdersTable
orders={orders}
onCancelClick={handleCancelClick}
onUpdateStatus={handleUpdateStatus}
/>

<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<UndeliverableOrders orders={undeliverableOrders} />
<OrderDetails />
{mounted && (
<DeliveryStatus
data={calculatePieChartData}
totalOrders={orders.length + undeliverableOrders.length}
totalOrders={orders.length}
/>
)}
</div>
</div>
);
}
}
Loading