diff --git a/README.md b/README.md index f0f7977..9169135 100644 --- a/README.md +++ b/README.md @@ -25,22 +25,14 @@ init POSTGRES Database - CREATE DATABASE drop_shopping; create tables - - timeSlots - - CREATE TABLE time_slots ( - id SERIAL PRIMARY KEY, - start_time TIME NOT NULL, - end_time TIME NOT NULL, - created_at TIMESTAMP DEFAULT NOW(), - updated_at TIMESTAMP DEFAULT NOW() - ); - - holidays - - CREATE TABLE holidays ( - id SERIAL PRIMARY KEY, - holiday_date DATE NOT NULL, - created_at TIMESTAMP DEFAULT NOW(), - updated_at TIMESTAMP DEFAULT NOW() - ); + CREATE TABLE deliveries ( + id SERIAL PRIMARY KEY, + user_id INTEGER NOT NULL, + slot_id INTEGER NOT NULL, + delivery_date DATE NOT NULL, + address TEXT NOT NULL, + status VARCHAR(10) NOT NULL +); knex for migration files diff --git a/package-lock.json b/package-lock.json index b324a5c..592c53b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,7 @@ }, "devDependencies": { "@types/node": "^18.16.0", + "@types/pg": "^8.6.6", "nodemon": "^2.0.22", "ts-node-dev": "^2.0.0", "typescript": "^5.0.4" @@ -134,6 +135,17 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.0.tgz", "integrity": "sha512-BsAaKhB+7X+H4GnSjGhJG9Qi8Tw+inU9nJDwmD5CgOmBLEI6ArdhikpLX7DjbjDRDTbqZzU2LSQNZg8WGPiSZQ==" }, + "node_modules/@types/pg": { + "version": "8.6.6", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.6.6.tgz", + "integrity": "sha512-O2xNmXebtwVekJDD+02udOncjVcMZQuTEQEMpKJ0ZRf5E7/9JJX3izhKUcUifBkyKpljyUM6BTgy2trmviKlpw==", + "dev": true, + "dependencies": { + "@types/node": "*", + "pg-protocol": "*", + "pg-types": "^2.2.0" + } + }, "node_modules/@types/qs": { "version": "6.9.7", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", diff --git a/package.json b/package.json index b5ee35a..531253f 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ }, "devDependencies": { "@types/node": "^18.16.0", + "@types/pg": "^8.6.6", "nodemon": "^2.0.22", "ts-node-dev": "^2.0.0", "typescript": "^5.0.4" diff --git a/src/app.ts b/src/app.ts index 7d3f4e2..6dad687 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,4 +1,5 @@ import express from 'express'; +const stam = 'fds' import routes from './routes'; const app = express(); diff --git a/src/handlers.ts b/src/handlers.ts index 86dab42..f1a66a5 100644 --- a/src/handlers.ts +++ b/src/handlers.ts @@ -1,42 +1,114 @@ import { Request, Response } from 'express'; import { resolveAddress } from './geocoding'; import { Address, AvailableTimeslots } from './types'; +import { randomUUID } from 'crypto'; // DOME import { getAvailableTimeSlots } from './services/timeslotsService'; import { getHolidays } from './services/holidaysService'; +const env = require('dotenv'); + +// create a hashing for caching delivery slots. this needs to be a caching db. +const deliveriesCache = new Map(); +// create a hashing for caching timeslots. this needs to be a caching db. +const slotsInUse = new Map(); + export const resolveAddressHandler = (req: Request, res: Response) => { - console.info("resolveAddressHandler called"); if (!req.body.searchTerm) { res.status(400).json({ error: 'Missing searchTerm' }); return; } const address: Promise
= resolveAddress(req.body.searchTerm); address.then((result) => { - console.info("resolveAddressHandler result: ", result); res.status(200).json(result); }) }; export const timeslotsHandler = async (req: Request, res: Response) => { - // TODO: Implement timeslots functionality if (!req.body.address) { res.status(400).json({ error: 'Missing address' }); return; } const address: Address = req.body.address; const timeSlots: AvailableTimeslots[] = await availableTimeSlots(address); - const availableTimeSlotsResult = await filterOutHolidaysByCountryCode(address, timeSlots); + const availableTimeSlotsResult: AvailableTimeslots[] = await filterOutHolidaysByCountryCode(address, timeSlots); + + availableTimeSlotsResult.forEach((timeSlot, index) => { + if (slotsInUse.has(timeSlot.id) && slotsInUse.get(timeSlot.id).length >= 2) { + availableTimeSlotsResult.splice(index, 1); + } + }); res.status(200).json(availableTimeSlotsResult); }; export const deliveriesHandler = (req: Request, res: Response) => { - // TODO: Implement deliveries functionality - + const userId = req.body.userId; + const slotId = req.body.timeslotId; + + // Idea: validate userId and slotId needed + if (!userId || !slotId) { + res.status(400).json({ error: 'Missing userId or slotId' }); + return; + } + + // Idea: check if user has already booked a delivery + // if (deliveriesCache.has(userId) && deliveriesCache.get(userId).slotId === slotId) { + // res.status(400).json({ error: 'User has already booked a delivery' }); + // return; + // } + + // Idea: check if timeslot is already full in cache + if (slotsInUse.has(slotId) && slotsInUse.get(slotId).length >= 2) { + res.status(400).json({ error: 'This timeslot is already full' }); + return; + } + const deliveryId = randomUUID(); + + // Idea: create new delivery for user + const delivery = { + _id: deliveryId, + userId, + slotId, + deliveryCreatedDate: new Date() + }; + if (slotsInUse.has(slotId)) { + slotsInUse.get(slotId).push(deliveryId); + } else { + slotsInUse.set(slotId, [deliveryId]); + } + deliveriesCache.set(deliveryId, delivery); + + console.log("deliveriesCache", deliveriesCache) + console.log("slotsInUse", slotsInUse) + res.status(200).json(delivery); }; + export const cancelDeliveryHandler = (req: Request, res: Response) => { // TODO: Implement cancel delivery functionality + // DELETE /deliveries/:deliveryId + const deliveryId = req.params.deliveryId; + + if (!deliveryId) { + res.status(400).json({ error: 'Missing deliveryId' }); + return; + } + + // remove from deliveriesCache and extract slotId + const delivery = deliveriesCache.get(deliveryId); + if (!delivery) { + res.status(400).json({ error: 'Delivery not found' }); + return; + } + const slotId = delivery.slotId; + deliveriesCache.delete(deliveryId); + // remove from slotsInUse by slotId + const slot = slotsInUse.get(slotId); + const index = slot.indexOf(deliveryId); + if (index > -1) { + slot.splice(index, 1); + } + res.status(200).json(delivery); }; export const dailyDeliveriesHandler = (req: Request, res: Response) => { @@ -49,18 +121,17 @@ export const weeklyDeliveriesHandler = (req: Request, res: Response) => { -async function filterOutHolidaysByCountryCode(address: Address, availableTimeSlot: AvailableTimeslots[]) { +async function filterOutHolidaysByCountryCode(address: Address, availableTimeSlot: AvailableTimeslots[]): Promise