diff --git a/backend/env.mjs b/backend/env.mjs new file mode 100644 index 0000000..58c5936 --- /dev/null +++ b/backend/env.mjs @@ -0,0 +1,2 @@ +export const EMAIL = "pramanickdebesh@gmail.com"; +export const PASSWORD = "hzgtirhzoqsdeltq"; \ No newline at end of file diff --git a/backend/index.js b/backend/index.js index b82a5f3..e2fe922 100644 --- a/backend/index.js +++ b/backend/index.js @@ -4,8 +4,7 @@ import cors from 'cors'; import { router } from './routes/routes.mjs'; const app = express(); -express.urlencoded() -//app.use(cookieParser()); +app.use(cookieParser()); app.use(cors({ origin: 'http://localhost:3000', // replace with your React app origin credentials: true, diff --git a/backend/logics/Availability/query.mjs b/backend/logics/Availability/query.mjs index d1eebb9..a22c84e 100644 --- a/backend/logics/Availability/query.mjs +++ b/backend/logics/Availability/query.mjs @@ -1,36 +1,25 @@ -import { gql } from 'graphql-request'; - -export const GET_AVAILABILITY = ` - query GetAvailability($eventName: String!) { - availability(where: { event_name: { _eq: $eventName } }) { - day - start_time - end_time - } - } -`; - -export const UPSERT_AVAILABILITY = ` - mutation UpsertAvailability($day: String!, $startTime: String!, $endTime: String!, $eventName: String!) { - insert_availability_one( - object: { day: $day, start_time: $startTime, end_time: $endTime, event_name: $eventName }, - on_conflict: { constraint: availability_day_start_time_event_name_key, update_columns: [end_time] } - ) { - id - day - start_time - end_time - event_name - } +export class SetAvailabilitySchema { + queryAvailability() { + return ` + mutation MyMutation($day: String!, $startTime: String!, $endTime: String!, $eventName: String!) { + insert_availability_one(object: {day: $day, start_time: $startTime, end_time: $endTime, event_name: $eventName}) { + id + day + start_time + end_time + event_name + } + } + `; } -`; - - -export const DELETE_AVAILABILITY = ` - mutation DeleteAvailability($day: String!, $startTime: String!, $eventName: String!) { - delete_availability(where: { day: { _eq: $day }, start_time: { _eq: $startTime }, event_name: { _eq: $eventName } }) { - affected_rows - } + deleteAvailability() { + return ` + mutation DeleteAvailability($day: String!, $startTime: String!, $eventName: String!) { + delete_availability(where: {day: {_eq: $day}, start_time: {_eq: $startTime}, event_name: {_eq: $eventName}}) { + affected_rows + } + } + `; } -`; +} diff --git a/backend/logics/Availability/setAvailQueries.mjs b/backend/logics/Availability/setAvailQueries.mjs index 1c90f45..f0516e6 100644 --- a/backend/logics/Availability/setAvailQueries.mjs +++ b/backend/logics/Availability/setAvailQueries.mjs @@ -1,81 +1,69 @@ -// import { GraphQLClient } from 'graphql-request'; -// import bodyParser from "body-parser"; -// import { SetAvailabilitySchema } from './query.mjs'; -// //import axios from 'axios'; -// //import gql from 'graphql-tag'; -// -// -// const new_availability = new SetAvailabilitySchema(); -// -// const hasuraEndpoint = 'http://localhost:8080/v1/graphql'; -// const adminSecret = '123'; -// const client = new GraphQLClient(hasuraEndpoint, { -// headers: { -// 'x-hasura-admin-secret': adminSecret -// // 'Authorization': `Bearer ${generateJwtToken()}` -// }, -// }); -// -// -// // Function to create availability -// export class setAvailability { -// set_availability(req, res) { -// for (const [day, slots] of Object.entries(req.body)) { -// slots.forEach(async slot => { // Note: Added 'async' here -// const { startTime, endTime } = slot; -// console.log(day, startTime, endTime); -// const eventName = req.params.eventName; -// //console.log(req.params); -// // Here you can call your function to insert the data into Hasura -// -// try { -// const response = await client.request(new_availability.queryAvailability(), { -// day, // Note: Changed 'weekday' to 'day' -// startTime, -// endTime, -// eventName -// }) -// console.log(response.data); -// } catch (error) { -// console.error('Failed to create event:', error); -// //res.status(500).json({success: false}); -// return; -// } -// }); -// } -// -// //res.status(200).json({success: "availability inserted"}); -// } -// async delete_availability(req, res) { -// const { day, startTime } = req.body; -// //console.log(req.body) -// const eventName = req.params.eventName -// console.log(eventName) -// try { -// const data = await client.request(new_availability.deleteAvailability(), { day, startTime ,eventName }); -// res.json({ success: true }); -// } catch (error) { -// console.error('Error occurred while deleting slot:', error); -// res.json({ success: false }); -// } -// } -// -// // async get_availability(req, res) { -// // const eventName = req.params.eventName; -// // try { -// // const data = await client.request(new_availability.getAvailability(), { eventName }); -// // res.json({ success: true, availability: data.availability }); -// // } catch (error) { -// // console.error('Error occurred while fetching availability:', error); -// // res.json({ success: false }); -// // } -// // } -// -// } -// -// -// -// -// -// +import { GraphQLClient } from 'graphql-request'; +import bodyParser from "body-parser"; +import { SetAvailabilitySchema } from './query.mjs'; +//import axios from 'axios'; +//import gql from 'graphql-tag'; + + +const new_availability = new SetAvailabilitySchema(); + +const hasuraEndpoint = 'http://localhost:8080/v1/graphql'; +const adminSecret = '123'; + +const client = new GraphQLClient(hasuraEndpoint, { + headers: { + 'x-hasura-admin-secret': adminSecret + // 'Authorization': `Bearer ${generateJwtToken()}` + }, +}); + + +// Function to create availability +export class setAvailability { + set_availability(req, res) { + for (const [day, slots] of Object.entries(req.body)) { + slots.forEach(async slot => { // Note: Added 'async' here + const { startTime, endTime } = slot; + console.log(day, startTime, endTime); + const {eventName} = req.params; + console.log(req.params); + // Here you can call your function to insert the data into Hasura + + try { + const response = await client.request(new_availability.queryAvailability(), { + day, // Note: Changed 'weekday' to 'day' + startTime, + endTime, + eventName + }) + console.log(response.data); + } catch (error) { + console.error('Failed to create event:', error); + //res.status(500).json({success: false}); + return; + } + }); + } + + //res.status(200).json({success: "availability inserted"}); + } + async delete_availability(req, res) { + const { day, startTime } = req.body; + const {eventName} = req.params; + console.log("*************************") + console.log(req.body) + try { + const data = await client.request(new_availability.deleteAvailability(), { day, startTime, eventName }); + res.json({ success: true }); + } catch (error) { + console.error('Error occurred while deleting slot:', error); + res.json({ success: false }); + } + } +} + + + + + diff --git a/backend/logics/GetEvents/getEvents.mjs b/backend/logics/GetEvents/getEvents.mjs index f0b6c98..ea7a21f 100644 --- a/backend/logics/GetEvents/getEvents.mjs +++ b/backend/logics/GetEvents/getEvents.mjs @@ -22,7 +22,9 @@ export class GetEvent{ try { const data = await client.request(get_events.GetEvents(),{}); - //console.log(data); + + // console.log(data.kalenview_create_events); + res.json(data.kalenview_create_events); // res.status(200).json({success:true}); } catch (error) { diff --git a/backend/logics/Mailer/mailer.mjs b/backend/logics/Mailer/mailer.mjs new file mode 100644 index 0000000..64cf594 --- /dev/null +++ b/backend/logics/Mailer/mailer.mjs @@ -0,0 +1,82 @@ +import nodemailer from 'nodemailer'; +import Mailgen from 'mailgen'; +import { EMAIL, PASSWORD } from '../../env.mjs'; + +export class Mailer { + + async send_real_mail(req, res) { + + const { eventType, eventDetail, userEmail, userName, day, eventName, date, startTime, endTime } = req.body; + console.log(userEmail, userName, day, eventName, date, startTime, endTime); // testmail@test.com New Name MON abcdef 2024-05-27 15:00 15:30 + + const config = { + service: 'gmail', + auth: { + user: EMAIL, + pass: PASSWORD + } + } + + const transporter = nodemailer.createTransport(config); + + const MailGenerator = new Mailgen({ + theme: "default", + product: { + name: "Event Scheduler of Kalenview ", + link: "https://mailgen.js" + } + }); + + const response = { + body: { + name: userName, + intro: `You have an upcoming event/meeting: ${eventName}`, + table: { + data: [ + { + 'Event Info' : 'Date', + description: date + }, + { + item: 'Day', + description: day + }, + { + item: 'Start Time', + description: startTime + }, + { + item: 'End Time', + description: endTime + }, + { + item: 'Event Location', + description: eventType + }, + { + item: 'Event Description', + description: eventDetail + } + ] + }, + outro: "Kindly be present there are per the scheduled time" + } + } + + const mail = MailGenerator.generate(response); + + let message = { + from: EMAIL, + to: [userEmail, "pramanickdebesh1412@gmail.com"], + subject: `Event Reminder: ${eventName}`, + html: mail + } + + transporter.sendMail(message).then(() => { + return res.status(201).json({ "msg": "Email is sent" }) + }).catch(error => { + return res.status(500).json({ error }) + }); + + } +} diff --git a/backend/logics/Register/query.mjs b/backend/logics/Register/query.mjs index f1c5e24..87f7852 100644 --- a/backend/logics/Register/query.mjs +++ b/backend/logics/Register/query.mjs @@ -1,18 +1,7 @@ export class RegisterEventQuery{ registerUser(){ return ` - mutation ($email: String!, $password: String!, $firstName: String!, $lastName: String!, $company: String!, $role: String!) { - insert_kalenview_one(object: { - email: $email, - password: $password, - first_name: $firstName, - last_name: $lastName, - company_name: $company, - company_role: $role - }) { - uuid - } - } + `; } } \ No newline at end of file diff --git a/backend/logics/VerifyJWT/verifyJWT.mjs b/backend/logics/VerifyJWT/verifyJWT.mjs index a8cb22d..1e3e701 100644 --- a/backend/logics/VerifyJWT/verifyJWT.mjs +++ b/backend/logics/VerifyJWT/verifyJWT.mjs @@ -21,7 +21,7 @@ export class VerifyJWToken{ } else{ - console.log("Valid jwt"); + console.log("Valid jwt !"); return res.status(200).json({success:true}); } diff --git a/backend/package-lock.json b/backend/package-lock.json index 7ae8270..f0dd890 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -13,7 +13,9 @@ "cors": "^2.8.5", "express": "^4.19.2", "graphql-request": "^7.0.1", - "jsonwebtoken": "^9.0.2" + "jsonwebtoken": "^9.0.2", + "mailgen": "^2.0.28", + "nodemailer": "^6.9.13" } }, "node_modules/@dprint/darwin-arm64": { @@ -167,6 +169,14 @@ "zod": "^3.17.3" } }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "engines": { + "node": ">=6" + } + }, "node_modules/ansi-regex": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", @@ -178,11 +188,35 @@ "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, + "node_modules/async": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, "node_modules/body-parser": { "version": "1.20.2", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", @@ -206,6 +240,20 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", @@ -248,6 +296,70 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/cheerio": { + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.10.tgz", + "integrity": "sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==", + "dependencies": { + "cheerio-select": "^1.5.0", + "dom-serializer": "^1.3.2", + "domhandler": "^4.2.0", + "htmlparser2": "^6.1.0", + "parse5": "^6.0.1", + "parse5-htmlparser2-tree-adapter": "^6.0.1", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/cheerio-select": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-1.6.0.tgz", + "integrity": "sha512-eq0GdBvxVFbqWgmCm7M3XGs1I8oLy/nExUnh6oLqmBditPO9AqQJrkslDpMun/hZ0yyTs8L0m85OHp4ho6Qm9g==", + "dependencies": { + "css-select": "^4.3.0", + "css-what": "^6.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.3.1", + "domutils": "^2.8.0" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -312,6 +424,32 @@ "node": ">= 0.10" } }, + "node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, "node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -353,6 +491,57 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, "node_modules/dprint": { "version": "0.45.1", "resolved": "https://registry.npmjs.org/dprint/-/dprint-0.45.1.tgz", @@ -384,6 +573,20 @@ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, + "node_modules/ejs": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -392,6 +595,14 @@ "node": ">= 0.8" } }, + "node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/es-define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", @@ -411,6 +622,17 @@ "node": ">= 0.4" } }, + "node_modules/escape-goat": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-3.0.0.tgz", + "integrity": "sha512-w3PwNZJwRxlp47QGzhuEBldEqVHHhh8/tIPcl6ecf2Bou99cdAt0knihBV0Ecc7CGxYduXVBDheH1K2oADRlvw==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -465,6 +687,33 @@ "node": ">= 0.10.0" } }, + "node_modules/filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/finalhandler": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", @@ -563,6 +812,14 @@ "graphql": "14 - 16" } }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, "node_modules/has-property-descriptors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", @@ -607,6 +864,32 @@ "node": ">= 0.4" } }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "bin": { + "he": "bin/he" + } + }, + "node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -646,6 +929,38 @@ "node": ">= 0.10" } }, + "node_modules/jake": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.1.tgz", + "integrity": "sha512-61btcOHNnLnsOdtLgA5efqQWjnSi/vow5HbI7HMdKKWqvrKR1bLK3BPlJn9gcSaP2ewuamUSMB5XEy76KUIS2w==", + "dependencies": { + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.4", + "minimatch": "^3.1.2" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jake/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/jsonwebtoken": { "version": "9.0.2", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", @@ -672,6 +987,24 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, + "node_modules/juice": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/juice/-/juice-8.1.0.tgz", + "integrity": "sha512-FLzurJrx5Iv1e7CfBSZH68dC04EEvXvvVvPYB7Vx1WAuhCp1ZPIMtqxc+WTWxVkpTIC2Ach/GAv0rQbtGf6YMA==", + "dependencies": { + "cheerio": "1.0.0-rc.10", + "commander": "^6.1.0", + "mensch": "^0.3.4", + "slick": "^1.12.2", + "web-resource-inliner": "^6.0.1" + }, + "bin": { + "juice": "bin/juice" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/jwa": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", @@ -741,6 +1074,16 @@ "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==" }, + "node_modules/mailgen": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mailgen/-/mailgen-2.0.28.tgz", + "integrity": "sha512-6g8vyKwMjAvNLuoDuGpJ4UhpvmroQQH9ZYzERC+/tL21Qvrzs2CM/li561rVIsSE+zroC4xSjXYYQ6pfPYYCXQ==", + "dependencies": { + "ejs": "^3.1.6", + "he": "^1.2.0", + "juice": "^8.0.0" + } + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -749,6 +1092,11 @@ "node": ">= 0.6" } }, + "node_modules/mensch": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/mensch/-/mensch-0.3.4.tgz", + "integrity": "sha512-IAeFvcOnV9V0Yk+bFhYR07O3yNina9ANIN5MoXBKYJ/RLYPurd2d0yw14MDhpr9/momp0WofT1bPUh3hkzdi/g==" + }, "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -792,6 +1140,17 @@ "node": ">= 0.6" } }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -805,6 +1164,44 @@ "node": ">= 0.6" } }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/nodemailer": { + "version": "6.9.13", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.13.tgz", + "integrity": "sha512-7o38Yogx6krdoBf3jCAqnIN4oSQFx+fMa0I7dK1D+me9kBxx12D+/33wSb+fhOCtIxvYJ+4x4IMEhmhCKfAiOA==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -832,6 +1229,19 @@ "node": ">= 0.8" } }, + "node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==" + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "dependencies": { + "parse5": "^6.0.1" + } + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -1021,6 +1431,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/slick": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/slick/-/slick-1.12.2.tgz", + "integrity": "sha512-4qdtOGcBjral6YIBCWJ0ljFSKNLz9KkhbWtuGvUyRowl1kxfuE1x/Z/aJcaiilpb3do9bl5K7/1h9XC5wWpY/A==", + "engines": { + "node": "*" + } + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -1057,6 +1475,17 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", @@ -1065,11 +1494,21 @@ "node": ">=0.6" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, "node_modules/ts-toolbelt": { "version": "9.6.0", "resolved": "https://registry.npmjs.org/ts-toolbelt/-/ts-toolbelt-9.6.0.tgz", "integrity": "sha512-nsZd8ZeNUzukXPlJmTBwUAuABDe/9qtVDelJeT/qW0ow3ZS3BsQJtNkan1802aM9Uf68/Y8ljw86Hu0h5IUW3w==" }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, "node_modules/type-fest": { "version": "4.18.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.18.2.tgz", @@ -1109,6 +1548,14 @@ "node": ">= 0.4.0" } }, + "node_modules/valid-data-url": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/valid-data-url/-/valid-data-url-3.0.1.tgz", + "integrity": "sha512-jOWVmzVceKlVVdwjNSenT4PbGghU0SBIizAev8ofZVgivk/TVHXSbNL8LP6M3spZvkR9/QolkyJavGSX5Cs0UA==", + "engines": { + "node": ">=10" + } + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -1117,6 +1564,75 @@ "node": ">= 0.8" } }, + "node_modules/web-resource-inliner": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/web-resource-inliner/-/web-resource-inliner-6.0.1.tgz", + "integrity": "sha512-kfqDxt5dTB1JhqsCUQVFDj0rmY+4HLwGQIsLPbyrsN9y9WV/1oFDSx3BQ4GfCv9X+jVeQ7rouTqwK53rA/7t8A==", + "dependencies": { + "ansi-colors": "^4.1.1", + "escape-goat": "^3.0.0", + "htmlparser2": "^5.0.0", + "mime": "^2.4.6", + "node-fetch": "^2.6.0", + "valid-data-url": "^3.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/web-resource-inliner/node_modules/domhandler": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.3.0.tgz", + "integrity": "sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==", + "dependencies": { + "domelementtype": "^2.0.1" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/web-resource-inliner/node_modules/htmlparser2": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-5.0.1.tgz", + "integrity": "sha512-vKZZra6CSe9qsJzh0BjBGXo8dvzNsq/oGvsjfRdOrrryfeD9UOBEEQdeoqCRmKZchF5h2zOBMQ6YuQ0uRUmdbQ==", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^3.3.0", + "domutils": "^2.4.2", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/fb55/htmlparser2?sponsor=1" + } + }, + "node_modules/web-resource-inliner/node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/zod": { "version": "3.23.8", "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", diff --git a/backend/package.json b/backend/package.json index a21fc5b..8c6644a 100644 --- a/backend/package.json +++ b/backend/package.json @@ -4,7 +4,9 @@ "cors": "^2.8.5", "express": "^4.19.2", "graphql-request": "^7.0.1", - "jsonwebtoken": "^9.0.2" + "jsonwebtoken": "^9.0.2", + "mailgen": "^2.0.28", + "nodemailer": "^6.9.13" }, "name": "backend", "version": "1.0.0", diff --git a/backend/routes/routes.mjs b/backend/routes/routes.mjs index 78f827f..aa5a2ce 100644 --- a/backend/routes/routes.mjs +++ b/backend/routes/routes.mjs @@ -2,7 +2,6 @@ import express from 'express'; // import { AuthLogic } from '../authintication/signup_login.mjs'; // import { NormRoutes } from '../normRoutes/linkpage.mjs'; // import { VerifyJwt } from '../verifyJWT/verifyjwt.mjs'; -import bodyParser from 'body-parser'; import { CreateEvent } from '../logics/CreateEvent/createEvent.mjs'; import { GetEvent } from '../logics/GetEvents/getEvents.mjs'; @@ -10,11 +9,11 @@ import { LoginUser } from '../logics/Login/login.mjs'; import { VerifyJWToken } from '../logics/VerifyJWT/verifyJWT.mjs'; import { ParticularEventDetails } from '../logics/EventDetails/eventDetail.mjs'; import { EditParticularEventDetails } from '../logics/EditEvent/editEvent.mjs'; +import { setAvailability } from '../logics/Availability/setAvailQueries.mjs'; +import { CreateUser } from '../logics/Register/registerUser.mjs'; +import { GetSlots } from '../logics/SelectSlot/slotSelect.mjs'; -//import { setAvailability } from '../logics/Availability/setAvailQueries.mjs'; - -//import {GetSlots} from "../logics/slotbook/getAvailQueries.mjs"; - +import { Mailer } from '../logics/Mailer/mailer.mjs'; // const auth_logic = new AuthLogic(); // const norm_routes = new NormRoutes(); @@ -26,15 +25,19 @@ const login_user = new LoginUser(); const jwt_verify = new VerifyJWToken(); const particular_event = new ParticularEventDetails(); const edit_Event = new EditParticularEventDetails(); +const availability = new setAvailability(); +const insert_user = new CreateUser(); +const getSlot = new GetSlots(); +const router = express.Router(); -//const availability = new setAvailability(); -//const getSlot = new GetSlots(); +const mail_message = new Mailer(); -const router = express.Router(); +// For Mail +router.post('/event/mail', mail_message.send_real_mail); -// For signup -router.post('/register', insert_user.create_user); +// // For signup +// router.post('/register', insert_user.create_user); // For login router.post('/login', login_user.login); @@ -42,37 +45,31 @@ router.post('/login', login_user.login); // For JWT Verification router.post('/verify', jwt_verify.verifyJWT); -// // For Home -// router.get('/', norm_routes.linkpage); +// // // For Home +// // router.get('/', norm_routes.linkpage); // For Create Event router.post('/events/create', new_event.create_event); -// For Get Event -router.get('/events', get_event.get_events); +// // For Get Event +// router.get('/events', get_event.get_events); -// For Get Event Details -router.get('/events/:eventName', particular_event.get_particular_event); +// // For Get Event Deatils +// router.get('/events/:eventName', particular_event.get_particular_event); -// For Edit Event Details -router.put('/events/:eventName', edit_Event.edit_particular_event); +// // For Edit Event Details +// router.put('/events/:eventName', edit_Event.edit_particular_event); -// For Set Availability +// // For Set Availability +// router.post('/events/availability/create/:eventName', availability.set_availability); +// router.post('/events/availability/delete/:eventName', availability.delete_availability); -//router.post('/events/availability/create/:eventName', availability.set_availability); +// // For Get Slots -//delete availability -//router.post(`/events/availability/delete/:eventName`, availability.delete_availability); -// router.post(`events/availability/delete/:eventName`,(req,res)=>{ -// console.log(req.body) -// }); +// router.get('/events/slots/:dayofWeek/:eventName', getSlot.get_slots); -//For get availability -//router.get('/events/slots/:dayofWeek/:eventName', getSlot.get_slots); -//console.log(getAvailability); -//router.get('/events/availability/:eventName', availability.get_availability); export {router}; \ No newline at end of file diff --git a/backend/test.js b/backend/test.js new file mode 100644 index 0000000..d4bb537 --- /dev/null +++ b/backend/test.js @@ -0,0 +1,251 @@ +import React, { useState, useEffect } from 'react'; +import { useParams } from 'react-router-dom'; +import { GraphQLClient } from 'graphql-request'; +import { GET_AVAILABILITY, UPSERT_AVAILABILITY, DELETE_AVAILABILITY } from './graphqlQueries'; +import './AvailabilityForm.css'; + +const graphqlClient = new GraphQLClient('http://localhost:8080/v1/graphql', { + headers: { + 'x-hasura-admin-secret': '123', + }, +}); + +const TimeSelect = ({ disabled, onChange, value }) => { + const times = []; + for (let i = 0; i < 24; i++) { + for (let j = 0; j < 60; j += 30) { + const time = `${i.toString().padStart(2, '0')}:${j.toString().padStart(2, '0')}`; + times.push(time); + } + } + + return ( + + ); +}; + +const AvailabilityForm = () => { + const daysOfWeek = ['MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT', 'SUN']; + const {eventName} = useParams(); + const [availability, setAvailability] = useState( + daysOfWeek.reduce((acc, day) => ({...acc, [day]: [{selected: false, startTime: '', endTime: ''}]}), {}) + ); + const [isFormValid, setIsFormValid] = useState(true); + + useEffect(() => { + const fetchAvailability = async () => { + try { + const response = await graphqlClient.request(GET_AVAILABILITY, {eventName}); + const fetchedAvailability = response.availability.reduce((acc, slot) => { + if (!acc[slot.day]) { + acc[slot.day] = []; + } + acc[slot.day].push({selected: true, startTime: slot.start_time, endTime: slot.end_time}); + return acc; + }, {}); + const newAvailability = {...availability}; + for (const day of daysOfWeek) { + if (fetchedAvailability[day]) { + newAvailability[day] = fetchedAvailability[day]; + } + } + setAvailability(newAvailability); + } catch (error) { + console.error('Failed to fetch availability:', error); + } + }; + + fetchAvailability(); + }, [eventName]); + + useEffect(() => { + const validateForm = () => { + for (const day in availability) { + const slots = availability[day]; + for (let i = 0; i < slots.length; i++) { + const slot = slots[i]; + if (slot.selected) { + if (slot.startTime >= slot.endTime) { + setIsFormValid(false); + return; + } + for (let j = 0; j < slots.length; j++) { + if (i !== j && slots[j].selected) { + if ( + (slot.startTime < slots[j].endTime && slot.endTime > slots[j].startTime) || + (slots[j].startTime < slot.endTime && slots[j].endTime > slot.startTime) + ) { + setIsFormValid(false); + return; + } + } + } + } + } + } + setIsFormValid(true); + }; + + validateForm(); + }, [availability]); + + const handleDayChange = (day, index) => async (event) => { + const updatedDaySlots = [...availability[day]]; + if (updatedDaySlots[index]) { + updatedDaySlots[index].selected = event.target.checked; + setAvailability({...availability, [day]: updatedDaySlots}); + + if (!event.target.checked) { + // Delete the slot if it's being deselected + const slotToDelete = availability[day][index]; + try { + const response = await graphqlClient.request(DELETE_AVAILABILITY, { + day: day, + startTime: slotToDelete.startTime, + eventName: eventName, + }); + if (response.delete_availability.affected_rows > 0) { + console.log('Slot deleted successfully'); + } else { + console.error('Failed to delete slot'); + } + } catch (e) { + console.error('Error occurred while deleting slot', e); + } + updatedDaySlots.splice(index, 1); + setAvailability({...availability, [day]: updatedDaySlots}); + } + } + }; + + const handleTimeChange = (day, index, timeType) => (event) => { + const updatedDaySlots = [...availability[day]]; + if (updatedDaySlots[index]) { + updatedDaySlots[index][timeType] = event.target.value; + setAvailability({...availability, [day]: updatedDaySlots}); + } + }; + + // const addTimeSlot = (day) => { + // setAvailability({ + // ...availability, + // [day]: [...availability[day], {selected: false, startTime: '', endTime: ''}] + // }); + // }; + + const deleteTimeSlot = async (day, index) => { + const slotToDelete = availability[day][index]; + try { + const response = await graphqlClient.request(DELETE_AVAILABILITY, { + day: day, + startTime: slotToDelete.startTime, + eventName: eventName, + }); + if (response.delete_availability.affected_rows > 0) { + console.log('Slot deleted successfully'); + } else { + console.error('Failed to delete slot'); + } + } catch (e) { + console.error('Error occurred while deleting slot', e); + } + + const updatedDaySlots = [...availability[day]]; + updatedDaySlots.splice(index, 1); + setAvailability({...availability, [day]: updatedDaySlots}); + }; + + const handleSubmit = async (event) => { + event.preventDefault(); + + const filteredAvailability = Object.fromEntries( + Object.entries(availability).filter(([day, slots]) => slots.some(slot => slot.selected)) + ); + + try { + let flag=0; + for (const [day, slots] of Object.entries(filteredAvailability)) { + for (const slot of slots) { + if (slot.selected) { + const data = await graphqlClient.request(UPSERT_AVAILABILITY, { + day: day, + startTime: slot.startTime, + endTime: slot.endTime, + eventName: eventName, + }); + console.log(data.insert_availability_one.event_name); + + if(!(data.insert_availability_one.event_name==eventName)){ + alert(`Availability will not set for Timeline:\n${day} ${slot.startTime}\nas it is already present in Event Name:\n${data.insert_availability_one.event_name}`); + flag+=1; + } + + } + } + } + if(flag!=1) { + alert('Availability set successfully!'); + } + } catch (e) { + console.error('Error occurred while setting availability', e); + alert('Failed to set availability'); + } + }; + + const addTimeSlot = (day) => { + setAvailability({ + ...availability, + [day]: [...availability[day], {selected: false, startTime: '', endTime: ''}] + }); + }; + + return ( +
+

WEEKLY HOURS

+
+
+ {daysOfWeek.map((day) => ( +
+

{day}

+ {availability[day].map((slot, index) => ( +
+ + + + {slot.selected && slot.startTime >= slot.endTime && +

Start time must be before end time

} + {slot.selected && ( + + )} +
+ ))} + +
+ ))} +
+ +
+
+ ); +} + +export default AvailabilityForm; + + + + + + + + + diff --git a/frontend/frontend/package-lock.json b/frontend/frontend/package-lock.json index 3e6fcbe..9f9d246 100644 --- a/frontend/frontend/package-lock.json +++ b/frontend/frontend/package-lock.json @@ -8,6 +8,8 @@ "name": "calendly-clone", "version": "0.1.0", "dependencies": { + "@fortawesome/free-solid-svg-icons": "^6.5.2", + "@fortawesome/react-fontawesome": "^0.2.1", "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", @@ -2485,6 +2487,52 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@fortawesome/fontawesome-common-types": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.5.2.tgz", + "integrity": "sha512-gBxPg3aVO6J0kpfHNILc+NMhXnqHumFxOmjYCFfOiLZfwhnnfhtsdA2hfJlDnj+8PjAs6kKQPenOTKj3Rf7zHw==", + "hasInstallScript": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/fontawesome-svg-core": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.5.2.tgz", + "integrity": "sha512-5CdaCBGl8Rh9ohNdxeeTMxIj8oc3KNBgIeLMvJosBMdslK/UnEB8rzyDRrbKdL1kDweqBPo4GT9wvnakHWucZw==", + "hasInstallScript": true, + "peer": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.5.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-solid-svg-icons": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.5.2.tgz", + "integrity": "sha512-QWFZYXFE7O1Gr1dTIp+D6UcFUF0qElOnZptpi7PBUMylJh+vFmIedVe1Ir6RM1t2tEQLLSV1k7bR4o92M+uqlw==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.5.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/react-fontawesome": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.1.tgz", + "integrity": "sha512-ldr5QO2MneAX5W5WBCYB2pZp/PiHDD1hy9YEBLcXUyJb0qnO86oP8RU+CgmYVSH/R4Dbe2ernhcWOrcgaKD9NQ==", + "dependencies": { + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "@fortawesome/fontawesome-svg-core": "~1 || ~6", + "react": ">=16.3" + } + }, "node_modules/@graphql-typed-document-node/core": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.2.0.tgz", diff --git a/frontend/frontend/package.json b/frontend/frontend/package.json index b6cf6a5..0b49b65 100644 --- a/frontend/frontend/package.json +++ b/frontend/frontend/package.json @@ -3,6 +3,8 @@ "version": "0.1.0", "private": true, "dependencies": { + "@fortawesome/free-solid-svg-icons": "^6.5.2", + "@fortawesome/react-fontawesome": "^0.2.1", "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", diff --git a/frontend/frontend/src/App.js b/frontend/frontend/src/App.js index 76e5633..6113a0a 100644 --- a/frontend/frontend/src/App.js +++ b/frontend/frontend/src/App.js @@ -1,34 +1,44 @@ import React from "react"; -import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; +import { BrowserRouter as Router, Routes, Route} from "react-router-dom"; import CreateEvent from "./components/CreateEvent/CreateEvent.js"; import EventList from "./components/EventList/EventList.js"; import Login from "./components/login/Login.js"; -import EventDetails from "./components/EventDetails/EventDetails.js"; +import EventDetails from "./components/EventDetails/EventDetailsCopy.js"; import AvailabilityForm from "./components/Availability/Avaiblity.js"; +import Register from "./components/Register/Register.js"; import CalendarPage from "./components/slotbook/slotbook"; import BookingPage from "./components/confirmpage/confirmpage"; import SuccessPage from "./components/successpage/successpage"; - import "./App.css"; function App() { return ( - -
- - } /> + //
+ // + //
+ + + +
+ + + } /> + + + } /> } /> } /> } /> } /> } /> } /> - } /> - -
-
+ } /> +
+
+
+ ); } -export default App; \ No newline at end of file +export default App; diff --git a/frontend/frontend/src/components/Availability/Avaiblity.js b/frontend/frontend/src/components/Availability/Avaiblity.js index a23015f..9dee373 100644 --- a/frontend/frontend/src/components/Availability/Avaiblity.js +++ b/frontend/frontend/src/components/Availability/Avaiblity.js @@ -167,19 +167,30 @@ const AvailabilityForm = () => { ); try { + let flag= false; for (const [day, slots] of Object.entries(filteredAvailability)) { for (const slot of slots) { if (slot.selected) { - await graphqlClient.request(UPSERT_AVAILABILITY, { + const data = await graphqlClient.request(UPSERT_AVAILABILITY, { day: day, startTime: slot.startTime, endTime: slot.endTime, eventName: eventName, }); + console.log(data.insert_availability_one.event_name); + + if(!(data.insert_availability_one.event_name===eventName)){ + alert(`Availability will not set for Timeline:\n${day} ${slot.startTime}\nas it is already present in Event Name:\n${data.insert_availability_one.event_name}`); + flag = true; + } + } } } - alert('Availability set successfully!'); + if(!flag) { + alert('Availability set successfully!'); + } + } catch (e) { console.error('Error occurred while setting availability', e); alert('Failed to set availability'); @@ -213,7 +224,7 @@ const AvailabilityForm = () => {

Start time must be before end time

} {slot.selected && ( + className="remove-button">X )} ))} diff --git a/frontend/frontend/src/components/Availability/AvaiblityCopy.js b/frontend/frontend/src/components/Availability/AvaiblityCopy.js new file mode 100644 index 0000000..3d1e758 --- /dev/null +++ b/frontend/frontend/src/components/Availability/AvaiblityCopy.js @@ -0,0 +1,211 @@ +import React, { useState, useEffect } from 'react'; +import { useEvent } from '../EventDetails/EventDetailsCopy'; +import { GraphQLClient } from 'graphql-request'; +import { useParams } from 'react-router-dom'; +import { UPSERT_AVAILABILITY, DELETE_AVAILABILITY } from './graphqlQueries'; +import './AvailabilityFormCopy.css'; + +const graphqlClient = new GraphQLClient('http://localhost:8080/v1/graphql', { + headers: { + 'x-hasura-admin-secret': '123', + }, +}); + +const TimeSelect = ({ disabled, onChange, value }) => { + const times = []; + for (let i = 0; i < 24; i++) { + for (let j = 0; j < 60; j += 30) { + const time = `${i.toString().padStart(2, '0')}:${j.toString().padStart(2, '0')}`; + times.push(time); + } + } + + return ( + + ); +}; + +const AvailabilityForm = () => { + const daysOfWeek = ['MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT', 'SUN']; + const {eventName} = useParams(); + const { availability, setAvailability } = useEvent(); + const [isFormValid, setIsFormValid] = useState(true); + + useEffect(() => { + const validateForm = () => { + for (const day in availability) { + const slots = availability[day]; + for (let i = 0; i < slots.length; i++) { + const slot = slots[i]; + if (slot.selected) { + if (slot.startTime >= slot.endTime) { + setIsFormValid(false); + return; + } + for (let j = 0; j < slots.length; j++) { + if (i !== j && slots[j].selected) { + if ( + (slot.startTime < slots[j].endTime && slot.endTime > slots[j].startTime) || + (slots[j].startTime < slot.endTime && slots[j].endTime > slot.startTime) + ) { + setIsFormValid(false); + return; + } + } + } + } + } + } + setIsFormValid(true); + }; + + validateForm(); + }, [availability]); + + const handleDayChange = (day, index) => async (event) => { + const updatedDaySlots = [...availability[day]]; + if (updatedDaySlots[index]) { + updatedDaySlots[index].selected = event.target.checked; + setAvailability({ ...availability, [day]: updatedDaySlots }); + + if (!event.target.checked) { + // Delete the slot if it's being deselected + const slotToDelete = availability[day][index]; + try { + const response = await graphqlClient.request(DELETE_AVAILABILITY, { + day: day, + startTime: slotToDelete.startTime, + eventName: eventName, + }); + if (response.delete_availability.affected_rows > 0) { + console.log('Slot deleted successfully'); + } else { + console.error('Failed to delete slot'); + } + } catch (e) { + console.error('Error occurred while deleting slot', e); + } + updatedDaySlots.splice(index, 1); + setAvailability({ ...availability, [day]: updatedDaySlots }); + } + } + }; + + const handleTimeChange = (day, index, timeType) => (event) => { + const updatedDaySlots = [...availability[day]]; + if (updatedDaySlots[index]) { + updatedDaySlots[index][timeType] = event.target.value; + setAvailability({ ...availability, [day]: updatedDaySlots }); + } + }; + + const handleSubmit = async (event) => { + event.preventDefault(); + + const filteredAvailability = Object.fromEntries( + Object.entries(availability).filter(([day, slots]) => slots.some(slot => slot.selected)) + ); + + try { + let flag = false; + for (const [day, slots] of Object.entries(filteredAvailability)) { + for (const slot of slots) { + if (slot.selected) { + const response = await graphqlClient.request(UPSERT_AVAILABILITY, { + eventName, + day, + startTime: slot.startTime, + endTime: slot.endTime, + }); + if(!(response.insert_availability_one.event_name===eventName)){ + alert(`Availability will not set for Timeline:\n${day} ${slot.startTime}\nas it is already present in Event Name:\n${response.insert_availability_one.event_name}`); + flag = true; + } + } + } + } + if (!flag) { + alert('Availability saved successfully.'); + } else { + alert('Failed to save some slots.'); + } + } catch (error) { + console.error('Failed to save availability:', error); + } + }; + + const addTimeSlot = (day) => { + const updatedDaySlots = [...(availability[day] || [])]; + updatedDaySlots.push({ selected: true, startTime: '00:00', endTime: '00:00' }); + setAvailability({ ...availability, [day]: updatedDaySlots }); + }; + + const deleteTimeSlot = (day, index) => async () => { + const updatedDaySlots = [...availability[day]]; + const slotToDelete = updatedDaySlots[index]; + if (slotToDelete) { + try { + const response = await graphqlClient.request(DELETE_AVAILABILITY, { + day: day, + startTime: slotToDelete.startTime, + eventName: eventName, + }); + if (response.delete_availability.affected_rows > 0) { + console.log('Slot deleted successfully'); + } else { + console.error('Failed to delete slot'); + } + } catch (e) { + console.error('Error occurred while deleting slot', e); + } + updatedDaySlots.splice(index, 1); + setAvailability({ ...availability, [day]: updatedDaySlots }); + } + }; + + return ( +
+
+ {daysOfWeek.map((day) => ( +
+

{day}

+ {availability[day]?.map((slot, index) => ( +
+ + + + +
+ ))} + +
+ ))} +
+ +
+ ); +}; + +export default AvailabilityForm; diff --git a/frontend/frontend/src/components/Availability/AvailabilityForm.css b/frontend/frontend/src/components/Availability/AvailabilityForm.css index 170f4ee..3e53310 100644 --- a/frontend/frontend/src/components/Availability/AvailabilityForm.css +++ b/frontend/frontend/src/components/Availability/AvailabilityForm.css @@ -1,65 +1,118 @@ +/* AvailabilityForm.css */ .availability-form { - display: flex; - flex-direction: column; - align-items: center; - } - - .title { - font-size: 24px; - font-weight: bold; - margin-bottom: 20px; - } - - .form { - width: 100%; - } - - .days-grid { - display: grid; - grid-template-columns: repeat(7, 1fr); - gap: 20px; - } - - .day { - display: flex; - flex-direction: column; - align-items: center; - } - - .day-name { - font-size: 18px; - font-weight: bold; - margin-bottom: 10px; - } - - .time-slot { - display: flex; - align-items: center; - margin-bottom: 10px; - } - - .add-slot-button { - margin-top: 10px; - } - - .submit-button { - margin-top: 20px; - } - - - /* AvailabilityForm.css */ + display: flex; + flex-direction: column; + align-items: center; + width: 80%; /* Adjust width to better fit the content */ + margin: 0 auto; /* Center the form */ + padding: 20px; /* Add padding for better spacing */ + background-color: #f9f9f9; /* Light background for contrast */ + border-radius: 20px; /* Rounded corners for better aesthetics */ + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* Subtle shadow for depth */ + border-color: #000000; +} + +.title { + font-size: 24px; + font-weight: bold; + margin-bottom: 20px; +} + +.form { + width: 100%; +} .days-grid { - display: grid; - grid-template-columns: repeat(2, 1fr); - gap: 10px; /* Reduce the gap between grid items */ - } - - .day { - display: flex; - flex-direction: column; - align-items: center; - padding: 5px; /* Reduce the padding */ - } - \ No newline at end of file + display: grid; + grid-template-columns: repeat(2, 1fr); /* Increase columns for more compact layout */ + gap: 10px; +} + +.day { + display: flex; + flex-direction: column; + align-items: center; + background-color: #fff; /* White background for each day */ + padding: 15px; /* Add padding for space */ + border-radius: 5px; /* Slight rounding for better aesthetics */ + box-shadow: 0 2px 4px rgba(7, 6, 6, 0.1); /* Light shadow for depth */ +} + +.day-name { + font-size: 18px; + font-weight: bold; + margin-bottom: 10px; + color: #333; /* Darker text color for better readability */ +} + +.time-slot { + display: flex; + align-items: center; + margin-bottom: 10px; + width: 100%; /* Full width for better alignment */ + justify-content: space-between; /* Space out elements evenly */ +} + +.time-slot select, .time-slot input[type="checkbox"] { + margin-right: 5px; /* Space out elements */ +} + +.time-slot .text-red-500 { + font-size: 12px; /* Smaller font for error message */ + margin-left: 5px; +} + +.add-slot-button { + margin-top: 10px; + padding: 5px 10px; /* Add padding for better click area */ + background-color: #4CAF50; /* Green background */ + color: white; /* White text */ + border: none; + border-radius: 5px; /* Rounded corners */ + cursor: pointer; /* Pointer cursor */ + transition: background-color 0.3s ease; /* Smooth transition */ +} + +.add-slot-button:hover { + background-color: #45a049; /* Darker green on hover */ +} + + +.remove-button button{ + background-color:#e53935; +} + +.submit-button { + margin-top: 20px; + padding: 10px 20px; /* Add padding for better click area */ + background-color: #008CBA; /* Blue background */ + color: white; /* White text */ + border: none; + border-radius: 5px; /* Rounded corners */ + cursor: pointer; /* Pointer cursor */ + transition: background-color 0.3s ease; /* Smooth transition */ +} + +.submit-button:disabled { + background-color: #ccc; /* Grey background when disabled */ + cursor: not-allowed; /* Not allowed cursor when disabled */ +} + +.submit-button:hover:not(:disabled) { + background-color: #007bb5; /* Darker blue on hover */ +} + +.time-slot button { + background-color: #f44336; /* Red background for delete button */ + color: white; /* White text */ + border: none; + border-radius: 5px; /* Rounded corners */ + padding: 5px 10px; /* Add padding for better click area */ + cursor: pointer; /* Pointer cursor */ + transition: background-color 0.3s ease; /* Smooth transition */ +} + +.time-slot button:hover { + background-color: #e53935; /* Darker red on hover */ +} diff --git a/frontend/frontend/src/components/Availability/AvailabilityFormCopy.css b/frontend/frontend/src/components/Availability/AvailabilityFormCopy.css new file mode 100644 index 0000000..8ecf970 --- /dev/null +++ b/frontend/frontend/src/components/Availability/AvailabilityFormCopy.css @@ -0,0 +1,69 @@ +.availability-form { + display: flex; + flex-direction: column; + align-items: center; + width: 80%; /* Adjust width to better fit the content */ + margin: 0 auto; /* Center the form */ + padding: 20px; /* Add padding for better spacing */ + background-color: #f9f9f9; /* Light background for contrast */ + border-radius: 20px; /* Rounded corners for better aesthetics */ + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* Subtle shadow for depth */ + border-color: #000000; +} + +.availability-day { + margin-bottom: 20px; /* Added margin between days for spacing */ + display: flex; + flex-direction: column; + align-items: center; + background-color: #fff; /* White background for each day */ + padding: 15px; /* Add padding for space */ + border-radius: 5px; /* Slight rounding for better aesthetics */ + box-shadow: 0 2px 4px; /* Light shadow for depth */ + +} + +.availability-slot { + display: flex; + align-items: center; + margin-bottom: 10px; +} + +.availability-slot input[type="checkbox"] { + margin-right: 10px; /* Added margin to separate checkbox from time inputs */ +} + +.availability-slot button { + margin-left: 10px; /* Added margin to separate delete button from time inputs */ + padding: 5px 10px; /* Adjusted padding for the delete button */ + border: none; + border-radius: 4px; + background-color: #f44336; /* Changed delete button background color */ + color: white; + cursor: pointer; +} + +.availability-slot button:hover { + background-color: #cc0000; /* Darkened delete button color on hover */ +} + +.availability-day h3 { + font-size: 18px; + font-weight: bold; + margin-bottom: 10px; +} + +button[type="submit"] { + margin-top: 20px; + padding: 10px 20px; + border: none; + border-radius: 4px; + background-color: #4CAF50; + color: white; + cursor: pointer; +} + +button[type="submit"]:disabled { + background-color: #cccccc; /* Changed disabled button background color */ + cursor: not-allowed; +} diff --git a/frontend/frontend/src/components/Availability/graphqlQueries.js b/frontend/frontend/src/components/Availability/graphqlQueries.js index 63bc964..3225583 100644 --- a/frontend/frontend/src/components/Availability/graphqlQueries.js +++ b/frontend/frontend/src/components/Availability/graphqlQueries.js @@ -14,7 +14,7 @@ export const UPSERT_AVAILABILITY = ` mutation UpsertAvailability($day: String!, $startTime: String!, $endTime: String!, $eventName: String!) { insert_availability_one( object: { day: $day, start_time: $startTime, end_time: $endTime, event_name: $eventName }, - on_conflict: { constraint: availability_day_start_time_event_name_key, update_columns: [end_time] } + on_conflict: { constraint: availability_day_start_time_key, update_columns: [end_time] } ) { id day diff --git a/frontend/frontend/src/components/EventDetails/EventDetails.css b/frontend/frontend/src/components/EventDetails/EventDetails.css index 7e7def1..26120b6 100644 --- a/frontend/frontend/src/components/EventDetails/EventDetails.css +++ b/frontend/frontend/src/components/EventDetails/EventDetails.css @@ -1,72 +1,69 @@ .event-details-container { - display: flex; - justify-content: space-between; - padding: 20px; - box-sizing: border-box; - } - - .event-edit, .event-details { - width: 50%; - padding: 20px; - box-sizing: border-box; - border: 1px solid #ccc; - border-radius: 4px; - } - - .event-edit form { - display: flex; - flex-direction: column; - } - - .event-edit form label { - margin-bottom: 10px; - } - - .event-edit form input { - margin-bottom: 20px; - padding: 10px; - border: 1px solid #ccc; - border-radius: 4px; - } - - .event-edit form button { - padding: 10px 20px; - border: none; - border-radius: 4px; - background-color: #4CAF50; - color: white; - cursor: pointer; - } - - .event-edit form button:hover { - background-color: #45a049; - } + display: flex; + justify-content: space-between; + padding: 20px; + box-sizing: border-box; +} + +.event-edit, .event-details { + width: 48%; + padding: 20px; + box-sizing: border-box; + border: 1px solid #ccc; + border-radius: 8px; + background-color: #f9f9f9; /* Light background for better contrast */ +} +.event-edit form { + display: flex; + flex-direction: column; +} - /* EventDetails.css */ +.event-edit form label { + margin-bottom: 10px; +} -.event-edit button { - display: block; /* Stack the buttons vertically */ - width: 100%; /* Make the buttons take up the full width of the container */ +.event-edit form input, +.event-edit form textarea { + margin-bottom: 20px; padding: 10px; - margin-bottom: 10px; /* Add some space between the buttons */ - font-size: 18px; /* Increase the font size */ + border: 1px solid #ccc; + border-radius: 4px; + width: 100%; +} + +.event-edit form button { + padding: 10px 20px; border: none; border-radius: 4px; - background-color: #3a5fb6; + background-color: #4CAF50; color: white; cursor: pointer; - text-align: center; + width: 100%; } -.event-edit button:hover { +.event-edit form button:hover { background-color: #45a049; } +.event-details h2 { + margin-top: 0; +} +.edit-button { + display: block; + width: 100%; + padding: 10px; + margin-bottom: 10px; + font-size: 18px; + border: none; + border-radius: 4px; + background-color: #3a5fb6; + color: white; + cursor: pointer; + text-align: center; +} - - - - - \ No newline at end of file +.edit-button:hover { + background-color: #2a47a6; +} diff --git a/frontend/frontend/src/components/EventDetails/EventDetails.js b/frontend/frontend/src/components/EventDetails/EventDetails.js index 1dc232b..74458b7 100644 --- a/frontend/frontend/src/components/EventDetails/EventDetails.js +++ b/frontend/frontend/src/components/EventDetails/EventDetails.js @@ -3,11 +3,11 @@ import { useParams } from 'react-router-dom'; import AvailabilityForm from '../Availability/Avaiblity'; import { GraphQLClient } from 'graphql-request'; import { GET_EVENT_DETAIL, UPDATE_EVENT_DETAIL } from './query'; -import './EventDetails.css'; // Import the CSS file +import './EventDetails.css'; const graphqlClient = new GraphQLClient('http://localhost:8080/v1/graphql', { headers: { - 'x-hasura-admin-secret': '123', // Replace with your actual admin secret or use a more secure method for authentication + 'x-hasura-admin-secret': '123', }, }); @@ -23,7 +23,7 @@ const EventDetails = () => { try { const response = await graphqlClient.request(GET_EVENT_DETAIL, { eventName }); setEvent(response.kalenview_create_events_by_pk); - setEditEvent(response.kalenview_create_events_by_pk); // Initialize editEvent with the fetched event data + setEditEvent(response.kalenview_create_events_by_pk); } catch (error) { console.error('Failed to fetch event:', error); } @@ -40,7 +40,6 @@ const EventDetails = () => { e.preventDefault(); try { - // Update the event details in the database const response = await graphqlClient.request(UPDATE_EVENT_DETAIL, { eventName, data: { @@ -51,9 +50,7 @@ const EventDetails = () => { }, }); - // Update the event details in the state setEvent(response.update_kalenview_create_events_by_pk); - // Hide the event edit after submitting setShowEditForm(false); } catch (error) { console.error('Failed to update event:', error); @@ -65,46 +62,47 @@ const EventDetails = () => { } return ( -
-
- +
+
+

Edit Event

+ - {showEditForm && ( -
- - - - - -
- )} + {showEditForm && ( +
+ + + +