Skip to content
Merged
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
2 changes: 2 additions & 0 deletions apps/backend/src/config/migrations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import { UpdateOrderEntity1769990652833 } from '../migrations/1769990652833-Upda
import { DonationItemFoodTypeNotNull1771524930613 } from '../migrations/1771524930613-DonationItemFoodTypeNotNull';
import { MoveRequestFieldsToOrders1770571145350 } from '../migrations/1770571145350-MoveRequestFieldsToOrders';
import { RenameDonationMatchingStatus1771260403657 } from '../migrations/1771260403657-RenameDonationMatchingStatus';
import { AddAssigneeToOrders1773009000618 } from '../migrations/1773009000618-AddAssigneeToOrders';
import { DropDonationTotalColumns1772241115031 } from '../migrations/1772241115031-DropDonationTotalColumns';
import { FixTrackingLinks1773041840374 } from '../migrations/1773041840374-FixTrackingLinks';
import { CleanupRequestsAndAllocations1771821377918 } from '../migrations/1771821377918-CleanupRequestsAndAllocations';
Expand Down Expand Up @@ -74,6 +75,7 @@ const schemaMigrations = [
DonationItemFoodTypeNotNull1771524930613,
MoveRequestFieldsToOrders1770571145350,
RenameDonationMatchingStatus1771260403657,
AddAssigneeToOrders1773009000618,
DropDonationTotalColumns1772241115031,
FixTrackingLinks1773041840374,
CleanupRequestsAndAllocations1771821377918,
Expand Down
30 changes: 30 additions & 0 deletions apps/backend/src/migrations/1773009000618-AddAssigneeToOrders.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { MigrationInterface, QueryRunner } from 'typeorm';

export class AddAssigneeToOrders1773009000618 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE orders ADD COLUMN assignee_id INT`);

await queryRunner.query(`
UPDATE orders o SET assignee_id = (
SELECT va.volunteer_id FROM volunteer_assignments va
JOIN food_requests fr ON fr.pantry_id = va.pantry_id
WHERE fr.request_id = o.request_id
LIMIT 1
)
`);

await queryRunner.query(`
ALTER TABLE orders
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also here we can edit the dummy data to add ids for the asignee for each order

ALTER COLUMN assignee_id SET NOT NULL,
ADD CONSTRAINT fk_assignee_id FOREIGN KEY (assignee_id) REFERENCES users(user_id) ON DELETE RESTRICT
`);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
ALTER TABLE orders
DROP CONSTRAINT IF EXISTS fk_assignee_id,
DROP COLUMN assignee_id
`);
}
}
8 changes: 8 additions & 0 deletions apps/backend/src/orders/order.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { FoodRequest } from '../foodRequests/request.entity';
import { FoodManufacturer } from '../foodManufacturers/manufacturers.entity';
import { OrderStatus } from './types';
import { Allocation } from '../allocations/allocations.entity';
import { User } from '../users/users.entity';

@Entity('orders')
export class Order {
Expand Down Expand Up @@ -99,4 +100,11 @@ export class Order {
},
})
shippingCost!: number | null;

@ManyToOne(() => User, { nullable: false, onDelete: 'RESTRICT' })
@JoinColumn({ name: 'assignee_id' })
assignee!: User;

@Column({ name: 'assignee_id', type: 'int' })
assigneeId!: number;
}
2 changes: 1 addition & 1 deletion apps/backend/src/orders/order.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,6 @@ describe('OrdersService', () => {
it('should update order with delivery details and set status to delivered but request remains active', async () => {
const orderRepo = testDataSource.getRepository(Order);
const requestRepo = testDataSource.getRepository(FoodRequest);

// Get an existing shipped order
const existingShippedOrder = await orderRepo.findOne({
where: { status: OrderStatus.SHIPPED },
Expand All @@ -594,6 +593,7 @@ describe('OrdersService', () => {
const secondOrder = orderRepo.create({
requestId: existingShippedOrder.requestId,
foodManufacturerId: existingShippedOrder.foodManufacturerId,
assigneeId: existingShippedOrder.assigneeId,
status: OrderStatus.SHIPPED,
shippedAt: new Date(),
});
Expand Down
8 changes: 4 additions & 4 deletions apps/backend/src/orders/order.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export class OrdersService {
.createQueryBuilder('order')
.leftJoinAndSelect('order.request', 'request')
.leftJoinAndSelect('request.pantry', 'pantry')
.leftJoinAndSelect('pantry.volunteers', 'volunteers')
.leftJoinAndSelect('order.assignee', 'assignee')
.select([
'order.orderId',
'order.status',
Expand All @@ -40,9 +40,9 @@ export class OrdersService {
'order.deliveredAt',
'request.pantryId',
'pantry.pantryName',
'volunteers.id',
'volunteers.firstName',
'volunteers.lastName',
'assignee.id',
'assignee.firstName',
'assignee.lastName',
]);

if (filters?.status) {
Expand Down
5 changes: 5 additions & 0 deletions apps/backend/src/users/users.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,11 @@ describe('UsersService', () => {

describe('remove', () => {
it('should remove a user by id', async () => {
await testDataSource.query(
`DELETE FROM allocations WHERE order_id IN (SELECT order_id FROM orders WHERE assignee_id = 6)`,
);
await testDataSource.query(`DELETE FROM orders WHERE assignee_id = 6`);

const result = await service.remove(6);

expect(result.email).toBe('james.t@volunteer.org');
Expand Down
3 changes: 2 additions & 1 deletion apps/backend/src/volunteers/volunteers.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@ describe('VolunteersService', () => {

describe('getVolunteersAndPantryAssignments', () => {
it('returns an empty array when there are no volunteers', async () => {
// Delete all users with role 'volunteer' (CASCADE will handle related data)
await testDataSource.query(`DELETE FROM allocations`);
await testDataSource.query(`DELETE FROM orders`);
await testDataSource.query(
`DELETE FROM "users" WHERE role = 'volunteer'`,
);
Expand Down
62 changes: 21 additions & 41 deletions apps/frontend/src/containers/adminOrderManagement.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -110,25 +110,15 @@ const AdminOrderManagement: React.FC = () => {
[OrderStatus.DELIVERED]: [],
};

// Use a status specific counter for assignee color assignment
const counters: Record<OrderStatus, number> = {
[OrderStatus.SHIPPED]: 0,
[OrderStatus.PENDING]: 0,
[OrderStatus.DELIVERED]: 0,
};

for (const order of data) {
const status = order.status;

const orderWithColor: OrderWithColor = { ...order };
if (
order.request.pantry.volunteers &&
order.request.pantry.volunteers.length > 0
) {

if (order.assignee) {
orderWithColor.assigneeColor =
ASSIGNEE_COLORS[counters[status] % ASSIGNEE_COLORS.length];
counters[status]++;
ASSIGNEE_COLORS[order.assignee.id % ASSIGNEE_COLORS.length];
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could we map user & color so a user across different orders would still be the same color?

this is used in volunteerManagement.tsx

ASSIGNEE_COLORS[assigneeCounter % ASSIGNEE_COLORS.length];
assigneeColorById.set(order.assignee.id, assigneeColor);

bg={ASSIGNEE_COLORS[order.assignee.id % ASSIGNEE_COLORS.length]}

grouped[status].push(orderWithColor);
}

Expand Down Expand Up @@ -614,7 +604,6 @@ const OrderStatusSection: React.FC<OrderStatusSectionProps> = ({
<Table.Body>
{orders.map((order, index) => {
const pantry = order.request.pantry;
const volunteers = pantry.volunteers || [];

return (
<Table.Row
Expand Down Expand Up @@ -664,28 +653,21 @@ const OrderStatusSection: React.FC<OrderStatusSectionProps> = ({
alignItems="center"
justifyContent="center"
>
{volunteers && volunteers.length > 0 ? (
<Box
key={index}
borderRadius="full"
bg={order.assigneeColor || 'gray'}
width="33px"
height="33px"
display="flex"
alignItems="center"
justifyContent="center"
color="white"
p={2}
>
{/* TODO: Change logic later to only get one volunteer */}
{getInitials(
volunteers[0].firstName,
volunteers[0].lastName,
)}
</Box>
) : (
<Box>No Assignees</Box>
)}
<Box
key={index}
borderRadius="full"
bg={order.assigneeColor || 'gray'}
width="33px"
height="33px"
display="flex"
alignItems="center"
justifyContent="center"
color="white"
p={2}
>
{order.assignee.firstName.charAt(0).toUpperCase()}
{order.assignee.lastName.charAt(0).toUpperCase()}
</Box>
</Box>
</Table.Cell>
<Table.Cell
Expand All @@ -708,10 +690,8 @@ const OrderStatusSection: React.FC<OrderStatusSectionProps> = ({
<Table.Cell
{...tableCellStyles}
textAlign="left"
color="neutral.700"
>
{/* TODO: IMPLEMENT WHAT GOES HERE */}
</Table.Cell>
bg="#FAFAFA"
></Table.Cell>
</Table.Row>
);
})}
Expand Down
5 changes: 5 additions & 0 deletions apps/frontend/src/types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,11 @@ export interface OrderSummary {
}[];
};
};
assignee: {
id: number;
firstName: string;
lastName: string;
};
}

export enum ApplicationStatus {
Expand Down
Loading