Skip to content
Snippets Groups Projects
Commit 07c1107a authored by Fin Wallis's avatar Fin Wallis
Browse files

Added forms for card details, as well as model and change to controller which...

Added forms for card details, as well as model and change to controller which now almost saves card details
parent dcd0946d
No related branches found
No related tags found
1 merge request!14Buy tickets, view owned tickets and miscellaneous files added
......@@ -46,3 +46,23 @@ exports.validatorResult = (req, res, next) => {
next();
}
// Validate postcode
function isPostcode(postcode) {
postcode = postcode.replace(/\s/g, "");
var regex = /^[A-Z]{1,2}[0-9]{1,2}[A-Z]{0,1} ?[0-9][A-Z]{2}$/i;
return regex.test(postcode);
}
// Validate purchase details
exports.purchaseValidator = [
body('addressLine1').not().isEmpty().trim().withMessage("Address line 1 is required"),
body('addressLine1').isLength({min: 3, max: 50}).withMessage("Address line 1 must be between 3 - 50 characters long"),
body('city').not().isEmpty().trim().withMessage("City is required"),
body('county').not().isEmpty().trim().withMessage("County is required"),
body('postCode').not().isEmpty().trim().withMessage("Postcode is required"),
body('cardholderName').isLength({min: 3, max: 50}).withMessage("Cardholder name must be 3 - 50 characters long"),
body('cardNumber').isLength({min: 16, max: 16}).withMessage("Card number must be 16 numbers"),
body('cardExpiryDate').isLength({min: 5, max: 5}).withMessage("Card expiry date must be valid"),
body('cardCVC').isLength({min: 3, max: 3}).withMessage("CVC number must be 3 numbers"),
]
import mongoose from 'mongoose';
import { EventSchema } from '../models/eventModel';
import { CardDetailSchema } from '../models/cardDetailModel';
// Creating event object
const Event = mongoose.model('Event', EventSchema);
// Creating card details object
const CardDetail = mongoose.model('CardDetail', CardDetailSchema);
exports.addNewEvent = async (req, res) => {
console.log("req body", req.body)
......@@ -72,6 +76,51 @@ export const getEvents = (req, res) => {
});
};
// export vs module exports (which works) - fix refactor later
exports.purchaseController = async (req, res) => {
console.log("inside controller", req.body);
// Destructuring sign up post request body into seperate variables for ref
const { addressLine1, addressLine2, city, county, postCode, cardholderName, cardNumber, cardExpiryDate, cardCVC, event_id, user_id } = req.body;
try {
// Could be implemented if letting user select the card number
// const card_detail = await CardDetail.findOne({ cardNumber });
// if (card_detail) {
// return res.status(400).json({
// errorMessage: "Email already in use",
// });
// }
// Creating new instance of user from model
const newCardDetail = new CardDetail();
// Assigning database fields to req fields
newCardDetail.addressLine1 = addressLine1;
newCardDetail.addressLine2 = addressLine2;
newCardDetail.city = city;
newCardDetail.county = county;
newCardDetail.postCode = postCode;
newCardDetail.cardholderName = cardholderName;
newCardDetail.cardNumber = cardNumber;
newCardDetail.cardExpiryDate = cardExpiryDate;
newCardDetail.cardCVC = cardCVC;
// await newCardDetail.save();
console.log(newCardDetail)
res.json({
successMessage: "Successfully signed up",
});
} catch (err) {
console.log("SignupController error:", err)
res.status(500).json({
errorMessage: "Server error"
})
}
};
......
import mongoose from 'mongoose';
const Schema = mongoose.Schema
export const CardDetailSchema = new Schema({
addressLine1: {
type: String,
required: true,
trim: true
},
addressLine2: {
type: String,
required: true,
trim: true
},
city: {
type: String,
required: true,
trim: true
},
county: {
type: String,
required: true,
trim: true
},
postCode: {
type: String,
required: true
},
cardholderName: {
type: String,
required: true
},
cardNumber: {
type: String,
required: true
},
cardExpiryDate: {
type: String,
required: true
},
cardCVC: {
type: String,
required: true
},
user_id: {
type: String,
required: true
},
})
const CardDetail = mongoose.model('CardDetail', CardDetailSchema);
module.exports = CardDetail
\ No newline at end of file
import mongoose from 'mongoose';
const Schema = mongoose.Schema
export const PurchaseSchema = new Schema({
user_id: {
type: String,
required: true,
},
event_id: {
type: String,
required: true,
},
card_details_id: {
type: String,
required: true,
},
})
const Purchase = mongoose.model('Purchase', PurchaseSchema);
module.exports = CardDetail
\ No newline at end of file
// Import controllers to connect to routes so the req can call the controller function based on the URL route
import {addNewEvent, getEvents} from "../controllers/eventControllers"
import {addNewEvent, getEvents, purchaseController} from "../controllers/eventControllers";
import { purchaseValidator, eventValidator, validatorResult } from "../Middleware/validator";
import {authenticateJWT} from "../middleware/authenticator"
import {upload} from "../middleware/multer"
import {eventValidator, validatorResult} from "../middleware/validator";
// upload.single("eventImage")
......@@ -10,6 +11,8 @@ const eventRoutes = (app) => {
app.route('/api/event')
.post(eventValidator, validatorResult, addNewEvent)
.get(getEvents)
app.route('/purchase')
.post(purchaseValidator, validatorResult, purchaseController)
};
......
......@@ -3,8 +3,7 @@ import React, { useEffect, useState } from "react";
import IconButton from "@mui/material/IconButton";
import ChevronRight from "@mui/icons-material/ChevronRight";
import ChevronLeft from "@mui/icons-material/ChevronLeft";
import isEmpty from 'validator/lib/isEmpty';
import {signUp} from '../api/auth';
import { signUp } from "../api/auth";
import Close from "@mui/icons-material/Close";
import Card from "@mui/material/Card";
import Grid from "@mui/material/Grid";
......@@ -14,6 +13,11 @@ import CardMedia from "@mui/material/CardMedia";
import Button from "@mui/material/Button";
import Typography from "@mui/material/Typography";
import { useNavigate } from "react-router-dom";
import isEmpty from "validator/lib/isEmpty";
import equals from "validator/lib/equals";
import errorAlert from "../Helpers/errorAlert";
import successAlert from "../Helpers/successAlert";
import { purchaseTicket } from "../api/events";
// Event card - Using material UI framework to bootstrap this process
// Event Data - Individual event data
......@@ -36,9 +40,13 @@ const EventCard = ({ eventData, type, setSelectedEvent, user }) => {
const [contactFormData, setContactFormData] = useState({
addressLine1: "1 Melville Road",
addressLine2: "",
city: "Falmouth",
county: "Cornwall",
postCode: "TR34 5TR",
city: "Devon",
county: "Devon",
postCode: "DV12 5TR",
cardholderName: "Fin Wallis",
cardNumber: 1111111111111111,
cardExpiryDate: "12/24",
cardCVC: 222,
errorMsg: false,
});
......@@ -49,7 +57,7 @@ const EventCard = ({ eventData, type, setSelectedEvent, user }) => {
return regex.test(postcode);
}
//When form values change on stage 2
// When form values change on stage 2
const handleContactFormChange = (event) => {
setContactFormData({
...contactFormData,
......@@ -59,7 +67,7 @@ const EventCard = ({ eventData, type, setSelectedEvent, user }) => {
console.log(contactFormData);
};
//When user clicks next on stage 2
// When user clicks next on stage 2
const handleContactSubmit = (event) => {
event.preventDefault();
console.log(contactFormData);
......@@ -81,32 +89,62 @@ const EventCard = ({ eventData, type, setSelectedEvent, user }) => {
errorMsg: "Invalid UK postcode",
});
} else {
const { addressLine1, addressLine2, city, county, postCode } =
contactFormData;
const data = { addressLine1, addressLine2, city, county, postCode };
const {
addressLine1,
addressLine2,
city,
county,
postCode,
cardholderName,
cardNumber,
cardExpiryDate,
cardCVC,
} = contactFormData;
console.log(user);
const data = {
addressLine1,
addressLine2,
city,
county,
postCode,
cardholderName,
cardNumber,
cardExpiryDate,
cardCVC,
event_id: eventData._id,
user_id: user._id,
};
console.log(data);
signUp(data)
purchaseTicket(data)
.then((response) => {
console.log("axios success", response);
// setFormData({
// firstName: "",
// lastName: "",
// email: "",
// password: "",
// confirmPassword: "",
// successMsg: response.data.successMessage,
// });
setContactFormData({
addressLine1: "",
addressLine2: "",
city: "",
county: "",
postCode: "",
cardholderName: "",
cardNumber: "",
cardExpiryDate: "",
cardCVC: "",
successMsg: response.data.successMessage,
});
})
.catch((err) => {
console.log("Axios error:", err);
// setFormData({
// ...formData,
// errorMsg: err.response.data.errorMessage,
// });
setContactFormData({
...contactFormData,
errorMsg: err.response.data.errorMessage,
});
});
}
};
console.log(Object.values(eventData));
return (
<>
{/* Small marketplace card */}
......@@ -320,41 +358,142 @@ const EventCard = ({ eventData, type, setSelectedEvent, user }) => {
</Grid>
)}
<Grid
container
item
justifyContent={"space-between"}
sx={{ height: "50px" }}
>
{stage === 1 ? (
{stage === 2 && (
<form
className="signup-form space-y-5 px-100"
onSubmit={handleContactSubmit}
noValidate
>
{contactFormData.errorMsg &&
errorAlert(contactFormData.errorMsg)}
{contactFormData.successMsg &&
successAlert(contactFormData.successMsg)}
<input
className="font-montserrat font-medium rounded-full w-full py-4 px-7 shadow-lg"
name="addressLine1"
value={contactFormData.addressLine1}
type="text"
placeholder="Address Line 1*"
onChange={handleContactFormChange}
></input>
<input
className="font-montserrat font-medium rounded-full w-full py-4 px-7 shadow-lg"
name="addressLine2"
value={contactFormData.addressLine2}
type="text"
placeholder="Address Line 2"
onChange={handleContactFormChange}
></input>
<input
className="font-montserrat font-medium rounded-full w-full py-4 px-7 shadow-lg"
name="city"
value={contactFormData.city}
type="text"
placeholder="City"
onChange={handleContactFormChange}
></input>
<input
className="font-montserrat font-medium rounded-full w-full py-4 px-7 shadow-lg"
name="county"
value={contactFormData.county}
type="text"
placeholder="County"
onChange={handleContactFormChange}
></input>
<input
className="font-montserrat font-medium rounded-full w-full py-4 px-7 shadow-lg"
name="postCode"
value={contactFormData.postCode}
type="text"
placeholder="Postcode"
onChange={handleContactFormChange}
></input>
<input
className="font-montserrat font-medium rounded-full w-full py-4 px-7 shadow-lg"
name="cardholderName"
value={contactFormData.cardholderName}
type="text"
placeholder="City"
onChange={handleContactFormChange}
></input>
<input
className="font-montserrat font-medium rounded-full w-full py-4 px-7 shadow-lg"
name="cardNumber"
value={contactFormData.cardNumber}
type="number"
minLength={16}
maxLength={16}
placeholder="County"
onChange={handleContactFormChange}
></input>
<input
className="font-montserrat font-medium rounded-full w-full py-4 px-7 shadow-lg"
name="cardExpiryDate"
value={contactFormData.cardExpiryDate}
type="string"
placeholder="Expiration Date"
onChange={handleContactFormChange}
></input>
<input
className="font-montserrat font-medium rounded-full w-full py-4 px-7 shadow-lg"
name="cardCVC"
value={contactFormData.cardCVC}
type="number"
minLength={3}
maxLength={3}
placeholder="CVC Number"
onChange={handleContactFormChange}
></input>
<Grid
container
item
justifyContent={"space-between"}
sx={{ height: "50px" }}
>
<IconButton
onPress={() => {
setStage(stage - 1);
}}
>
Back
</IconButton>
<button
className="py-4 px-14 text-white bg-purple-500 hover:bg-purple-400 font-montserrat font-medium rounded-full"
type="submit"
>
Buy ticket for £{eventData.ticketPrice}
</button>
</Grid>
</form>
)}
{stage === 1 && (
<Grid
container
item
justifyContent={"space-between"}
sx={{ height: "50px" }}
>
<IconButton
onPress={() => {
setStage(stage + 1);
setShowBuyTicket(false);
}}
>
Cancel
</IconButton>
) : (
<IconButton
onPress={() => {
onClick={() => {
setStage(stage + 1);
console.log(stage);
}}
>
<ChevronLeft />
Back
Next
<ChevronRight />
</IconButton>
)}
<IconButton
onClick={() => {
setStage(stage + 1);
console.log(stage);
}}
>
Next
<ChevronRight />
</IconButton>
</Grid>
</Grid>
)}
</>
)}
</Grid>
......
......@@ -20,6 +20,7 @@ const Marketplace = () => {
useEffect(() => {
async function getEvents() {
let tickets = await getAllEvents();
console.log(tickets.data)
setAllEvents(tickets.data);
}
getEvents();
......
......@@ -27,9 +27,9 @@ export const getAllEvents = async () => {
const response = await axios.get('/api/event', config)
return response
};
};
export const purchaseTicket = async (event_id, user_id) => {
export const purchaseTicket = async (data) => {
const config = {
headers: {
......@@ -37,7 +37,7 @@ export const purchaseTicket = async (event_id, user_id) => {
}
}
const response = await axios.get('/purchase/'+event_id+'/'+user_id, config)
const response = await axios.post('/purchase/',data, config)
return response
};
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment