diff --git a/README.md b/README.md index 90ac910..f0f7977 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,30 @@ install pg MacOS - Start Postgres - brew services start postgresql + + Postgres CLI - + psql postgres + +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() + ); knex for migration files diff --git a/src/data/holidays.json b/src/data/holidays.json index 94832df..3cc938b 100644 --- a/src/data/holidays.json +++ b/src/data/holidays.json @@ -1,7 +1,17 @@ -{ - "holidays": [ - "2023-05-01", - "2023-06-12", - "2023-09-25" + [ + { + "name": "New Year's Day", + "date": "2023-01-17", + "country": "US" + }, + { + "name": "Mother's Day", + "date": "2023-09-18", + "country": "US" + }, + { + "name": "Independence Day", + "date": "2023-09-17", + "country": "GB" + } ] -} \ No newline at end of file diff --git a/src/data/timeSlots.json b/src/data/timeSlots.json index 5bdab5d..069a62f 100644 --- a/src/data/timeSlots.json +++ b/src/data/timeSlots.json @@ -1,10 +1,39 @@ { - "timeSlots": [ - "08:00 - 10:00", - "10:00 - 12:00", - "12:00 - 14:00", - "14:00 - 16:00", - "16:00 - 18:00", - "18:00 - 20:00" + "courier_available_timeslots": [ + { + "start_time": "2023-09-17 08:00:00", + "end_time": "2023-09-17 09:00:00", + "supported_postcodes": [ + "W1H 1LJ", + "2222222" + ] + }, + { + "start_time": "2023-09-17 09:00:00", + "end_time": "2023-09-17 10:00:00", + "supported_postcodes": [ + "1111111", + "2222222", + "3333333" + ] + }, + { + "start_time": "2023-09-17 09:00:00", + "end_time": "2023-09-17 10:00:00", + "supported_postcodes": [ + "4444444", + "5555555", + "6666666" + ] + }, + { + "start_time": "2023-09-18 14:00:00", + "end_time": "2023-09-18 15:00:00", + "supported_postcodes": [ + "W1H 1LJ", + "5555555", + "6666666" + ] + } ] } \ No newline at end of file diff --git a/src/geocoding.ts b/src/geocoding.ts index ba1b69c..2d6f690 100644 --- a/src/geocoding.ts +++ b/src/geocoding.ts @@ -13,12 +13,14 @@ export const resolveAddress = async (searchTerm: string): Promise
=> { const response = await axios.get(`https://api.geoapify.com/v1/geocode/search?text=${searchTerm}&format=json&apiKey=${GEOCODING_API_KEY}`); if (response.data.results.length > 0) { const result = response.data.results[0]; + console.log(result) return { country: result.country, street: result.street, line1: result.address_line1, line2: result.address_line2, - postcode: result.postcode + postcode: result.postcode, + code: result.country_code.toUpperCase() } } else { throw new Error('No results found'); diff --git a/src/handlers.ts b/src/handlers.ts index c6010c2..f7e365b 100644 --- a/src/handlers.ts +++ b/src/handlers.ts @@ -1,25 +1,35 @@ import { Request, Response } from 'express'; import { resolveAddress } from './geocoding'; -import { Address } from './types'; +import { Address, AvailableTimeslots } from './types'; // DOME import { getAvailableTimeSlots } from './services/timeslotsService'; import { getHolidays } from './services/holidaysService'; 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 = (req: Request, res: Response) => { - // TODO: Implement timeslots functionality - - + }) }; - + +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); + res.status(200).json(availableTimeSlotsResult); +}; + export const deliveriesHandler = (req: Request, res: Response) => { // TODO: Implement deliveries functionality }; @@ -35,3 +45,41 @@ export const dailyDeliveriesHandler = (req: Request, res: Response) => { export const weeklyDeliveriesHandler = (req: Request, res: Response) => { // TODO: Implement weekly deliveries functionality }; + + + +async function filterOutHolidaysByCountryCode(address: Address, availableTimeSlot: AvailableTimeslots[]) { + const countryCode = address.code; + const holidays = await getHolidays(); + + const filteredAvailableTimeSlot = []; + + + console.log(availableTimeSlot) + holidays.forEach((holiday) => { + if(holiday.country === countryCode) { + availableTimeSlot.forEach((timeSlot) => { + if(timeSlot.start_time.split(' ')[0] !== holiday.date) { + filteredAvailableTimeSlot.push(timeSlot) + } + }) + } + }); + return filteredAvailableTimeSlot; +} + + +async function availableTimeSlots(address: Address) { + const availableTimeSlot = []; + const timeslots = await getAvailableTimeSlots(); + // check by postcode if any available timeslots + for (const timeslot of timeslots.courier_available_timeslots) { + if (timeslot.supported_postcodes.includes(address.postcode)) { + availableTimeSlot.push({ + start_time: timeslot.start_time, + end_time: timeslot.end_time + }); + } + } + return availableTimeSlot; +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index a915a01..17a358f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,40 +8,52 @@ app.listen(PORT, () => { console.log("STARTING ... ") if (env === 'development') { console.log("Generating mock data files") - generateMockDataFiles(); + // generateMockDataFiles(); } console.log(`Server is running on port ${PORT}`); }); -const generateMockDataFiles = () => { +// const generateMockDataFiles = () => { - if (!fs.existsSync('./data')) { - fs.mkdirSync('./data'); - } +// if (!fs.existsSync('./data')) { +// fs.mkdirSync('./data'); +// } - if (!fs.existsSync('./data/timeSlots.json')) { - const timeSlots = { - timeSlots: [ - "08:00 - 10:00", - "10:00 - 12:00", - "12:00 - 14:00", - "14:00 - 16:00", - "16:00 - 18:00", - "18:00 - 20:00" - ] - } - fs.writeFileSync('./data/timeSlots.json', JSON.stringify(timeSlots)); - } - - if (!fs.existsSync('./data/holidays.json')) { - const holidays = { - holidays: [ - "2023-05-01", - "2023-06-12", - "2023-09-25" - ] - } - fs.writeFileSync('./data/holidays.json', JSON.stringify(holidays)); - } -} \ No newline at end of file +// if (!fs.existsSync('./data/timeSlots.json')) { +// const timeSlots = { +// timeSlots: [ +// "08:00 - 10:00", +// "10:00 - 12:00", +// "12:00 - 14:00", +// "14:00 - 16:00", +// "16:00 - 18:00", +// "18:00 - 20:00" +// ] +// } +// fs.writeFileSync('./data/timeSlots.json', JSON.stringify(timeSlots)); +// } + +// if (!fs.existsSync('./data/holidays.json')) { +// const holidays = { +// "holidays": [ +// { +// "name": "New Year's Day", +// "date": "2023-01-17", +// "country": "US" +// }, +// { +// "name": "Mother's Day", +// "date": "2023-09-18", +// "country": "US" +// }, +// { +// "name": "Independence Day", +// "date": "2023-10-17", +// "country": "US" +// } +// ] +// } +// fs.writeFileSync('./data/holidays.json', JSON.stringify(holidays)); +// } +// } \ No newline at end of file diff --git a/src/routes.ts b/src/routes.ts index 4572c05..112da50 100644 --- a/src/routes.ts +++ b/src/routes.ts @@ -4,9 +4,9 @@ import { resolveAddressHandler, timeslotsHandler, deliveriesHandler, cancelDeliv const router = express.Router(); router.post('/resolve-address', resolveAddressHandler); +router.post('/timeslots', timeslotsHandler); router.get('/deliveries/daily', dailyDeliveriesHandler); router.get('/deliveries/weekly', weeklyDeliveriesHandler); -router.post('/timeslots', timeslotsHandler); router.post('/deliveries', deliveriesHandler); router.delete('/deliveries/:id', cancelDeliveryHandler); diff --git a/src/seed/load-data.js b/src/seeds/load-data.js similarity index 82% rename from src/seed/load-data.js rename to src/seeds/load-data.js index 3d9b7fd..b7f2cdd 100644 --- a/src/seed/load-data.js +++ b/src/seeds/load-data.js @@ -12,9 +12,15 @@ exports.seed = async function(knex) { const holidays = require('../data/holidays.json'); const timeslots = require('../data/timeslots.json'); + console.log(holidays) // Insert the holiday dates into the holidays table for (const date of holidays) { - await knex('holidays').insert({ date }); + console.log(date) + await knex('holidays').insert( { + name: "test", + date: "2020-12-25", + country: "US" + } ); } // Insert the time slots into the timeslots table diff --git a/src/types/index.ts b/src/types/index.ts index 4434d69..8080343 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -4,4 +4,10 @@ export interface Address { line2: string; country: string; postcode: string; -} \ No newline at end of file + code: string; +} + +export interface AvailableTimeslots { + start_time: string; + end_time: string; +} \ No newline at end of file