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
127 changes: 87 additions & 40 deletions src/controllers/facility.controller.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { NextFunction, Request, Response } from "express";

// Extend Express Request interface to include decodeuser
declare global {
namespace Express {
interface Request {
Expand All @@ -17,7 +16,7 @@ import {
getAllFacility_ByFiltering,
getFacilitiesByOperator,
updateFacilityCapacity,
searchFacilities,
searchEverythingGlobally,
} from "../services/db/facility.service";
import { StatusCodes } from "http-status-codes";
import {
Expand All @@ -27,7 +26,6 @@ import {
} from "../errors/errors";
import { PrismaClient } from "@prisma/client";
import { deleteImageFromCloudinary } from "../services/cloudinary.service";
import { FacilityFilterOptions } from "../types/types";
const prisma = new PrismaClient();

export const addFacility = async (
Expand Down Expand Up @@ -267,52 +265,101 @@ export const updateCapacity = async (
}
};


export const globalFacilitySearch = async (
req: Request,
res: Response,
next: NextFunction
) => {
try {
const {
location,
type,
available,
operatorName,
minPrice,
maxPrice,
page = "1",
limit = "10",
} = req.query;

const allowedTypes = [
"DRYER",
"STORAGE",
"PROCESSING",
"COLDROOM",
"OTHER",
] as const;
type FacilityType = (typeof allowedTypes)[number];

const filters: FacilityFilterOptions = {
location: location as string,
type: allowedTypes.includes(type as FacilityType)
? (type as FacilityType)
: undefined,
available:
available === "true" ? true : available === "false" ? false : undefined,
operatorName: operatorName as string,
minPrice: minPrice ? Number(minPrice) : undefined,
maxPrice: maxPrice ? Number(maxPrice) : undefined,
page: Number(page),
limit: Number(limit),
};
const { term = "", page = 1, limit = 10 } = req.query;
const userId = req.currentUser?.id;
const userRole = req.currentUser?.role;

if (!userId) {
res.status(StatusCodes.UNAUTHORIZED).json({
message: "Authentication required"
});
return
}

const response = await searchFacilities(filters);
const results = await searchEverythingGlobally(
term as string,
userId,
userRole,
Number(page),
Number(limit)
);

res.status(200).json({
message: "Facilities fetched successfully",
data: response,
res.status(StatusCodes.OK).json({
message: "Search results fetched successfully",
data: results,
});

} catch (error) {
next(error);
}
};


export const getOperatorAvailableFacilities = async (
req: Request,
res: Response,
next: NextFunction
) => {
try {
const operator = req.operator;

if (!operator) {
throw new UnauthorizedError({
message: "Operator not authorized",
from: "getOperatorsAvailableFacilities controller"
});
}

const today = new Date();
today.setHours(0, 0, 0, 0);

const endOfToday = new Date(today.getTime() + 24 * 60 * 60 * 1000);

const facilities = await prisma.facility.findMany({
where: { operatorId: operator.id },
});

if (!facilities.length) {
res.status(StatusCodes.OK).json({
message: "Operator has no facilities",
facilities: [],
});
return;
}

const facilityIds = facilities.map((f) => f.id);

const bookedToday = await prisma.booking.findMany({
where: {
facilityId: { in: facilityIds },
startDate: {
gte: today,
lt: endOfToday,
},
status: {
in: ["RESERVED", "CONFIRMED"],
},
},
});

const bookedFacilityIds = new Set(bookedToday.map((b) => b.facilityId));

const availableFacilities = facilities.filter(
(f) => !bookedFacilityIds.has(f.id)
);

res.status(StatusCodes.OK).json({
message: "Available facilities fetched successfully",
facilities: availableFacilities,
});

} catch (error) {
next(error);
}
Expand Down
4 changes: 2 additions & 2 deletions src/routes/facility.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import express from 'express';
import { facilityValidator } from '../utils/validateFacility';
import { verifyAuth } from '../middlewares/authenticate.middleware';
import { isAuthorizedOperator, isOperator, isFacilityOwner } from '../middlewares/authorization.middlewares';
import { addFacility, getFacility, updateFacility, getAllFacilityByFiltering, deleteFacility, updateCapacity , deleteFacilityImage, getFacilitiesByOperatorController, globalFacilitySearch, getOperatorsAvailableFacilities } from '../controllers/facility.controller';
import { addFacility, getFacility, updateFacility, getAllFacilityByFiltering, deleteFacility, updateCapacity , deleteFacilityImage, getFacilitiesByOperatorController, globalFacilitySearch, getOperatorAvailableFacilities } from '../controllers/facility.controller';

import { upload } from '../config/config.cloudinary';
import { uploadFacilityImage } from '../controllers/cloudinary.controller';
Expand All @@ -14,7 +14,7 @@ router.post('/', verifyAuth, facilityValidator, addFacility);
router.get('/', verifyAuth, getAllFacilityByFiltering); //Allows filtering and no filtering
router.get('/search', verifyAuth, globalFacilitySearch)
router.get('/all', verifyAuth, isAuthorizedOperator, getFacilitiesByOperatorController);
router.get('/available/today', verifyAuth, isAuthorizedOperator, getOperatorsAvailableFacilities);
router.get('/available/today', verifyAuth, isAuthorizedOperator, getOperatorAvailableFacilities);
router.post('/images', verifyAuth, isOperator, upload.array('images', 5), uploadFacilityImage);


Expand Down
Loading