| @@ -12,6 +12,7 @@ import Link from 'next/link'; | |||
| import PropType from 'prop-types'; | |||
| import React from 'react'; | |||
| import { BASE_PAGE } from '../../../constants/pages'; | |||
| import { postQuestion } from '../../../requests/question/postQuestionRequest'; | |||
| import { contactPageSchema } from '../../../schemas/contactSchema'; | |||
| const ContactPageForm = () => { | |||
| @@ -19,7 +20,11 @@ const ContactPageForm = () => { | |||
| //const [error] = useState({ hasError: false, errorMessage: '' }); | |||
| const handleSubmit = async (values) => { | |||
| console.log(values); | |||
| try { | |||
| postQuestion(values); | |||
| } catch (error) { | |||
| console.log(error); | |||
| } | |||
| }; | |||
| const formik = useFormik({ | |||
| @@ -0,0 +1,39 @@ | |||
| const mongoose = require('mongoose'); | |||
| const validator = require('validator'); | |||
| const QuestionSchema = new mongoose.Schema({ | |||
| firstName: { | |||
| type: String, | |||
| required: [true, 'Please provide a name.'], | |||
| maxlength: [60, 'Name cannot be more than 60 characters'], | |||
| trim: true, | |||
| }, | |||
| lastName: { | |||
| type: String, | |||
| required: [true, 'Please provide a last name.'], | |||
| maxlength: [60, 'Name cannot be more than 60 characters'], | |||
| trim: true, | |||
| }, | |||
| email: { | |||
| type: String, | |||
| unique: [true, 'Email must be unique.'], | |||
| required: [true, 'Please provide an email.'], | |||
| trim: true, | |||
| lowercase: true, | |||
| validate(value) { | |||
| if (!validator.isEmail(value)) { | |||
| throw new Error('Email is invalid'); | |||
| } | |||
| }, | |||
| }, | |||
| message: { | |||
| type: String, | |||
| required: [true, 'Please provide a message/question.'], | |||
| trim: true, | |||
| }, | |||
| }); | |||
| const Question = | |||
| mongoose.models.Question || | |||
| mongoose.model('Question', QuestionSchema, 'Questions'); | |||
| module.exports = Question; | |||
| @@ -9,6 +9,7 @@ const nextConfig = { | |||
| NEXT_PUBLIC_STRIPE_PUBLIC_API_KEY: | |||
| process.env.NEXT_PUBLIC_STRIPE_PUBLIC_API_KEY, | |||
| NEXT_PUBLIC_MAP_KEY: process.env.NEXT_PUBLIC_NEXT_PUBLIC_MAP_KEY, | |||
| NEXT_PUBLIC_SEND_GRID: process.env.NEXT_PUBLIC_SEND_GRID, | |||
| }, | |||
| reactStrictMode: true, | |||
| swcMinify: true, | |||
| @@ -19,6 +19,7 @@ | |||
| "@mui/icons-material": "^5.8.4", | |||
| "@mui/material": "^5.9.2", | |||
| "@react-google-maps/api": "^2.12.2", | |||
| "@sendgrid/mail": "^7.7.0", | |||
| "@stripe/stripe-js": "^1.35.0", | |||
| "@tanstack/react-query": "^4.0.10", | |||
| "bcryptjs": "^2.4.3", | |||
| @@ -1,6 +1,18 @@ | |||
| const Product = require('../../../models/product'); | |||
| import dbConnect from '../../../utils/helpers/dbHelpers'; | |||
| const shuffle = function (v) { | |||
| //+ Jonas Raoni Soares Silva | |||
| //@ http://jsfromhell.com/array/shuffle [rev. #1] | |||
| for ( | |||
| var j, x, i = v.length; | |||
| i; | |||
| j = parseInt(Math.random() * i), x = v[--i], v[i] = v[j], v[j] = x | |||
| ); | |||
| return v; | |||
| }; | |||
| async function handler(req, res) { | |||
| const { method } = req; | |||
| @@ -17,9 +29,19 @@ async function handler(req, res) { | |||
| throw new Error('The product with this id does not exist!'); | |||
| } | |||
| const similarProducts = await Product.find({ | |||
| category: product.category, | |||
| customID: { $ne: product.customID }, | |||
| }); | |||
| const shuffled = similarProducts | |||
| .sort(() => 0.5 - Math.random()) | |||
| .slice(0, 3); | |||
| res.status(200).json({ | |||
| message: 'The product you requested was fetched successfully.', | |||
| product, | |||
| similarProducts: shuffled, | |||
| }); | |||
| } catch (error) { | |||
| res.status(400).json({ message: error.message }); | |||
| @@ -0,0 +1,49 @@ | |||
| const Question = require('../../../models/question'); | |||
| import dbConnect from '../../../utils/helpers/dbHelpers'; | |||
| const sgMail = require('@sendgrid/mail'); | |||
| async function handler(req, res) { | |||
| const { method } = req; | |||
| await dbConnect(); | |||
| switch (method) { | |||
| case 'POST': { | |||
| try { | |||
| const question = await Question.create(req.body); | |||
| sgMail.setApiKey(process.env.NEXT_PUBLIC_SEND_GRID); | |||
| const msg = { | |||
| to: 'nikola.tasic@dilig.net', //req.body.email, // Change to your recipient | |||
| from: 'nikola.tasic@dilig.net', // Change to your verified sender | |||
| subject: 'Question submitted', | |||
| text: 'Your question was submitted successfully, we will contact you via email shortly. Thank you!', | |||
| html: '<strong>Your question was submitted successfully, we will contact you via email shortly. Thank you!</strong>', | |||
| }; | |||
| sgMail | |||
| .send(msg) | |||
| .then(() => { | |||
| console.log('Email sent'); | |||
| }) | |||
| .catch((error) => { | |||
| res.status(400).json({ message: error }); | |||
| }); | |||
| res.status(201).json({ | |||
| message: | |||
| 'Your message/question was submitted successfully, check your mail for confirmation.', | |||
| question, | |||
| }); | |||
| } catch (error) { | |||
| res.status(400).json({ message: error }); | |||
| } | |||
| break; | |||
| } | |||
| default: | |||
| res.status(405).json({ message: 'Method not allowed' }); | |||
| break; | |||
| } | |||
| } | |||
| export default handler; | |||
| @@ -8,4 +8,5 @@ export default { | |||
| featuredProducts: '/api/product/featured-products', | |||
| order: '/api/order', | |||
| userUpdate: '/api/user', | |||
| question: '/api/question', | |||
| }; | |||
| @@ -0,0 +1,19 @@ | |||
| import apiEndpoints from '../apiEndpoints'; | |||
| export const postQuestion = async (questionData) => { | |||
| const response = await fetch(apiEndpoints.question, { | |||
| method: 'POST', | |||
| body: JSON.stringify(questionData), | |||
| headers: { | |||
| 'Content-Type': 'application/json', | |||
| }, | |||
| }); | |||
| const data = await response.json(); | |||
| if (!response.ok) { | |||
| throw new Error(data.message || 'Something went wrong!'); | |||
| } | |||
| return data; | |||
| }; | |||
| @@ -1937,6 +1937,30 @@ | |||
| resolved "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.1.4.tgz" | |||
| integrity sha512-LwzQKA4vzIct1zNZzBmRKI9QuNpLgTQMEjsQLf3BXuGYb3QPTP4Yjf6mkdX+X1mYttZ808QpOwAzZjv28kq7DA== | |||
| "@sendgrid/client@^7.7.0": | |||
| version "7.7.0" | |||
| resolved "https://registry.yarnpkg.com/@sendgrid/client/-/client-7.7.0.tgz#f8f67abd604205a0d0b1af091b61517ef465fdbf" | |||
| integrity sha512-SxH+y8jeAQSnDavrTD0uGDXYIIkFylCo+eDofVmZLQ0f862nnqbC3Vd1ej6b7Le7lboyzQF6F7Fodv02rYspuA== | |||
| dependencies: | |||
| "@sendgrid/helpers" "^7.7.0" | |||
| axios "^0.26.0" | |||
| "@sendgrid/helpers@^7.7.0": | |||
| version "7.7.0" | |||
| resolved "https://registry.yarnpkg.com/@sendgrid/helpers/-/helpers-7.7.0.tgz#93fb4b6e2f0dc65080440d6a784cc93e8e148757" | |||
| integrity sha512-3AsAxfN3GDBcXoZ/y1mzAAbKzTtUZ5+ZrHOmWQ279AuaFXUNCh9bPnRpN504bgveTqoW+11IzPg3I0WVgDINpw== | |||
| dependencies: | |||
| deepmerge "^4.2.2" | |||
| "@sendgrid/mail@^7.7.0": | |||
| version "7.7.0" | |||
| resolved "https://registry.yarnpkg.com/@sendgrid/mail/-/mail-7.7.0.tgz#aba09f5ce2e9d8ceee92284c3ea8b4a90b0e38fe" | |||
| integrity sha512-5+nApPE9wINBvHSUxwOxkkQqM/IAAaBYoP9hw7WwgDNQPxraruVqHizeTitVtKGiqWCKm2mnjh4XGN3fvFLqaw== | |||
| dependencies: | |||
| "@sendgrid/client" "^7.7.0" | |||
| "@sendgrid/helpers" "^7.7.0" | |||
| "@storybook/addon-actions@6.5.9", "@storybook/addon-actions@^6.5.9": | |||
| version "6.5.9" | |||
| resolved "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-6.5.9.tgz" | |||
| @@ -3855,6 +3879,13 @@ axe-core@^4.4.3: | |||
| resolved "https://registry.npmjs.org/axe-core/-/axe-core-4.4.3.tgz" | |||
| integrity sha512-32+ub6kkdhhWick/UjvEwRchgoetXqTK14INLqbGm5U2TzBkBNF3nQtLYm8ovxSkQWArjEQvftCKryjZaATu3w== | |||
| axios@^0.26.0: | |||
| version "0.26.1" | |||
| resolved "https://registry.yarnpkg.com/axios/-/axios-0.26.1.tgz#1ede41c51fcf51bbbd6fd43669caaa4f0495aaa9" | |||
| integrity sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA== | |||
| dependencies: | |||
| follow-redirects "^1.14.8" | |||
| axobject-query@^2.2.0: | |||
| version "2.2.0" | |||
| resolved "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz" | |||
| @@ -5858,6 +5889,11 @@ focus-lock@^0.8.0: | |||
| dependencies: | |||
| tslib "^1.9.3" | |||
| follow-redirects@^1.14.8: | |||
| version "1.15.2" | |||
| resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" | |||
| integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== | |||
| for-in@^1.0.2: | |||
| version "1.0.2" | |||
| resolved "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz" | |||
| @@ -7893,6 +7929,37 @@ mkdirp@^0.5.1: | |||
| dependencies: | |||
| minimist "^1.2.6" | |||
| mkdirp@^1.0.3, mkdirp@^1.0.4: | |||
| version "1.0.4" | |||
| resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz" | |||
| integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== | |||
| dependencies: | |||
| yallist "^4.0.0" | |||
| minizlib@^2.1.1: | |||
| version "2.1.2" | |||
| resolved "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz" | |||
| integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== | |||
| dependencies: | |||
| minipass "^3.0.0" | |||
| yallist "^4.0.0" | |||
| mixin-deep@^1.2.0: | |||
| version "1.3.2" | |||
| resolved "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz" | |||
| integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== | |||
| dependencies: | |||
| for-in "^1.0.2" | |||
| is-extendable "^1.0.1" | |||
| mkdirp@^0.5.1: | |||
| version "0.5.6" | |||
| resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz" | |||
| integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== | |||
| dependencies: | |||
| minimist "^1.2.6" | |||
| mkdirp@^1.0.3, mkdirp@^1.0.4: | |||
| version "1.0.4" | |||
| resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz" | |||