Skip to content

Commit aea2c59

Browse files
authored
Merge pull request #20 from Code-4-Community/food-request-form
Food request form
2 parents c513598 + bd48e43 commit aea2c59

File tree

9 files changed

+373
-238
lines changed

9 files changed

+373
-238
lines changed

apps/backend/src/app.module.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Module } from '@nestjs/common';
22
import { TypeOrmModule } from '@nestjs/typeorm';
3-
3+
import { RequestsModule } from './foodRequests/request.module';
44
import { AppController } from './app.controller';
55
import { AppService } from './app.service';
66
import { UsersModule } from './users/users.module';
@@ -22,6 +22,7 @@ import typeorm from './config/typeorm';
2222
}),
2323
UsersModule,
2424
AuthModule,
25+
RequestsModule,
2526
],
2627
controllers: [AppController],
2728
providers: [AppService],
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import {
2+
Controller,
3+
Get,
4+
Param,
5+
ParseIntPipe,
6+
Post,
7+
Body,
8+
} from '@nestjs/common';
9+
import { ApiBody } from '@nestjs/swagger';
10+
import { RequestsService } from './request.service';
11+
import { FoodRequest } from './request.entity';
12+
13+
@Controller('requests')
14+
//@UseInterceptors()
15+
export class FoodRequestsController {
16+
constructor(private requestsService: RequestsService) {}
17+
18+
@Get('/:pantryId')
19+
async getAllPantryRequests(
20+
@Param('pantryId', ParseIntPipe) pantryId: number,
21+
): Promise<FoodRequest[]> {
22+
return this.requestsService.find(pantryId);
23+
}
24+
25+
@Post('/create')
26+
@ApiBody({
27+
description: 'Details for creating a food request',
28+
schema: {
29+
type: 'object',
30+
properties: {
31+
pantryId: { type: 'integer', example: 1 },
32+
requestedSize: { type: 'string', example: 'Medium (5-10 boxes)' },
33+
requestedItems: {
34+
type: 'array',
35+
items: { type: 'string' },
36+
example: ['Rice Noodles', 'Quinoa'],
37+
},
38+
additionalInformation: {
39+
type: 'string',
40+
nullable: true,
41+
example: 'Urgent request',
42+
},
43+
status: { type: 'string', example: 'pending' },
44+
fulfilledBy: { type: 'integer', nullable: true, example: null },
45+
dateReceived: {
46+
type: 'string',
47+
format: 'date-time',
48+
nullable: true,
49+
example: null,
50+
},
51+
feedback: { type: 'string', nullable: true, example: null },
52+
photos: {
53+
type: 'array',
54+
items: { type: 'string' },
55+
nullable: true,
56+
example: [],
57+
},
58+
},
59+
},
60+
})
61+
async createRequest(
62+
@Body()
63+
body: {
64+
pantryId: number;
65+
requestedSize: string;
66+
requestedItems: string[];
67+
additionalInformation: string;
68+
status: string;
69+
fulfilledBy: number;
70+
dateReceived: Date;
71+
feedback: string;
72+
photos: string[];
73+
},
74+
): Promise<FoodRequest> {
75+
return this.requestsService.create(
76+
body.pantryId,
77+
body.requestedSize,
78+
body.requestedItems,
79+
body.additionalInformation,
80+
body.status,
81+
body.fulfilledBy,
82+
body.dateReceived,
83+
body.feedback,
84+
body.photos,
85+
);
86+
}
87+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import {
2+
Entity,
3+
Column,
4+
PrimaryGeneratedColumn,
5+
CreateDateColumn,
6+
} from 'typeorm';
7+
8+
@Entity('food_requests')
9+
export class FoodRequest {
10+
@PrimaryGeneratedColumn({ name: 'request_id' })
11+
requestId: number;
12+
13+
@Column({ name: 'pantry_id', type: 'int' })
14+
pantryId: number;
15+
16+
@Column({ name: 'requested_size', type: 'varchar', length: 50 })
17+
requestedSize: string;
18+
19+
@Column({ name: 'requested_items', type: 'text', array: true })
20+
requestedItems: string[];
21+
22+
@Column({ name: 'additional_information', type: 'text', nullable: true })
23+
additionalInformation: string;
24+
25+
@CreateDateColumn({
26+
name: 'requested_at',
27+
type: 'timestamp',
28+
default: () => 'NOW()',
29+
})
30+
requestedAt: Date;
31+
32+
@Column({ name: 'status', type: 'varchar', length: 25, default: 'pending' })
33+
status: string;
34+
35+
@Column({ name: 'fulfilled_by', type: 'int', nullable: true })
36+
fulfilledBy: number;
37+
38+
@Column({ name: 'date_received', type: 'timestamp', nullable: true })
39+
dateReceived: Date;
40+
41+
@Column({ name: 'feedback', type: 'text', nullable: true })
42+
feedback: string;
43+
44+
@Column({ name: 'photos', type: 'text', array: true, nullable: true })
45+
photos: string[];
46+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { Module } from '@nestjs/common';
2+
import { TypeOrmModule } from '@nestjs/typeorm';
3+
import { FoodRequestsController } from './request.controller';
4+
import { FoodRequest } from './request.entity';
5+
import { RequestsService } from './request.service';
6+
import { JwtStrategy } from '../auth/jwt.strategy';
7+
import { AuthService } from '../auth/auth.service';
8+
9+
@Module({
10+
imports: [TypeOrmModule.forFeature([FoodRequest])],
11+
controllers: [FoodRequestsController],
12+
providers: [RequestsService, AuthService, JwtStrategy],
13+
})
14+
export class RequestsModule {}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { Injectable, NotFoundException } from '@nestjs/common';
2+
import { InjectRepository } from '@nestjs/typeorm';
3+
import { Repository } from 'typeorm';
4+
5+
import { FoodRequest } from './request.entity';
6+
7+
@Injectable()
8+
export class RequestsService {
9+
constructor(
10+
@InjectRepository(FoodRequest) private repo: Repository<FoodRequest>,
11+
) {}
12+
13+
async create(
14+
pantryId: number,
15+
requestedSize: string,
16+
requestedItems: string[],
17+
additionalInformation: string | null,
18+
status: string = 'pending',
19+
fulfilledBy: number | null,
20+
dateReceived: Date | null,
21+
feedback: string | null,
22+
photos: string[] | null,
23+
) {
24+
const foodRequest = this.repo.create({
25+
pantryId,
26+
requestedSize,
27+
requestedItems,
28+
additionalInformation,
29+
status,
30+
fulfilledBy,
31+
dateReceived,
32+
feedback,
33+
photos,
34+
});
35+
36+
return this.repo.save(foodRequest);
37+
}
38+
39+
find(pantryId: number) {
40+
if (!pantryId || pantryId < 1) {
41+
throw new NotFoundException('Invalid pantry ID');
42+
}
43+
return this.repo.find({ where: { pantryId } });
44+
}
45+
}

apps/frontend/src/app.tsx

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,12 @@ import { createBrowserRouter, RouterProvider } from 'react-router-dom';
44
import apiClient from '@api/apiClient';
55
import Root from '@containers/root';
66
import NotFound from '@containers/404';
7-
import { submitFoodRequestForm } from '@components/forms/foodRequestForm';
8-
import RequestFood from '@containers/foodRequest';
97
import LandingPage from '@containers/landingPage';
108
import PantryOverview from '@containers/pantryOverview';
119
import PantryPastOrders from '@containers/pantryPastOrders';
1210
import Pantries from '@containers/pantries';
1311
import Orders from '@containers/orders';
12+
import { submitFoodRequestFormModal } from '@components/forms/requestFormModalButton';
1413

1514
const router = createBrowserRouter([
1615
{
@@ -38,13 +37,12 @@ const router = createBrowserRouter([
3837
path: '/orders',
3938
element: <Orders />,
4039
},
40+
{
41+
path: '/food-request', // The route to handle form submission
42+
action: submitFoodRequestFormModal, // Action function to handle the form data and redirection
43+
},
4144
],
4245
},
43-
{
44-
path: '/food-request',
45-
element: <RequestFood />,
46-
action: submitFoodRequestForm,
47-
},
4846
]);
4947

5048
export const App: React.FC = () => {

0 commit comments

Comments
 (0)