diff --git a/backend/main.py b/backend/main.py index f263ea1..1abf7e4 100644 --- a/backend/main.py +++ b/backend/main.py @@ -35,6 +35,32 @@ def upload(): return redirect('/') +@app.route("/mail", methods=["POST"]) +def mail(): + email = request.json["email"] + password = request.json["password"] + order = request.json["order"] + + + if email is None: + return jsonify({"error": "Unauthorized"}), 401 + + if not bcrypt.check_password_hash(user.password, password): + return jsonify({"error": "Unauthorized"}), 401 + + # Cache session with redis + session["user_id"] = user.id + + return jsonify({ + "id": user.id, + "email": user.email + }) + +@app.route("/orders", methods=["GET"]) +def orders(): + + + # Handle Images @app.route('/serve-image/', methods=['GET']) def serve_image(filename): diff --git a/backend/models.py b/backend/models.py index 0bc5b6f..b8ff370 100644 --- a/backend/models.py +++ b/backend/models.py @@ -24,6 +24,23 @@ class User(db.Model): id = db.Column(db.String(32), primary_key=True, unique=True, default=get_uuid) email = db.Column(db.String(345), unique=True) password = db.Column(db.Text, nullable=False) + +class Orders(db.Model): + __tablename__ ="orders" + id = db.Column(db.Integer, primary_key=True) + name = db.Column(db.String(80), unique=False, nullable=False) + email = db.Column(db.String(120), unique=False, nullable=False) + order = db.Column(db.String(345), unique=False, nullable=False) + + + + def to_json(self): + return { + "id": self.id, + "firstName":self.first_name, + "lastName":self.last_name, + "email": self.email, + } # class Category(db.Model): # __tablename__ = "categories" diff --git a/frontend/bun.lockb b/frontend/bun.lockb index f2e0eb7..08a46ef 100755 Binary files a/frontend/bun.lockb and b/frontend/bun.lockb differ diff --git a/frontend/package.json b/frontend/package.json index f95751f..3a806de 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -14,21 +14,23 @@ "clsx": "^2.1.1", "lucide-react": "^0.427.0", "next": "14.1.4", - "react": "^18", + "nodemailer": "^6.9.14", + "react": "^18.3.1", "react-dom": "^18.3.1", "sharp": "^0.33.4", - "tailwind-merge": "^2.5.0", + "tailwind-merge": "^2.5.2", "tailwindcss-animate": "^1.0.7" }, "devDependencies": { - "typescript": "^5", - "@types/node": "^20", - "@types/react": "^18", - "@types/react-dom": "^18", - "autoprefixer": "^10.0.1", - "postcss": "^8", - "tailwindcss": "^3.3.0", - "eslint": "^8", - "eslint-config-next": "14.1.4" + "@types/node": "^20.14.15", + "@types/nodemailer": "^6.4.15", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "autoprefixer": "^10.4.20", + "eslint": "^8.57.0", + "eslint-config-next": "14.1.4", + "postcss": "^8.4.41", + "tailwindcss": "^3.4.10", + "typescript": "^5.5.4" } } diff --git a/frontend/src/app/api/emails/route.ts b/frontend/src/app/api/emails/route.ts new file mode 100644 index 0000000..db97005 --- /dev/null +++ b/frontend/src/app/api/emails/route.ts @@ -0,0 +1,26 @@ +export async function POST() { + const sender = { + name: 'My App', + address: 'no-reply@kevosattire.com', + } + + const recipients = [{ + name: 'John Doe', + address: 'fernando.delgado@kevosattire.com', + }] + + try{ + const result = await sendEmail({ + sender, + recipients, + subject: "Thank you for placing an order with us!", + message: "We will follow up with a Paypal invoice soon!" + }) + + return Response.json({ + accepted: result.accepted, + }) + } catch (error){ + return Response.json({message: 'Unable to send email at this time.'}, {status: 500}) + } +} \ No newline at end of file diff --git a/frontend/src/components/Form/Form.tsx b/frontend/src/components/Form/Form.tsx new file mode 100644 index 0000000..52df101 --- /dev/null +++ b/frontend/src/components/Form/Form.tsx @@ -0,0 +1,33 @@ +"use client"; +import * as React from "react"; + +const Form = () => { + const [result, setResult] = React.useState>({}); + const [loading, setLoading] = React.useState(false); + + const sendEmail = () => { + setLoading(true); + + fetch('/api/emails', { + method: 'POST' + }) + .then(response => response.json()) + .then(data => setResult(data)) + .catch(error => setResult(error)) + .finally(() => setLoading(false)) + }; + + return ( +
+
{JSON.stringify(result)}
+ + {loading &&
Processing...
} + + +
+ ); +}; + +export default Form; diff --git a/frontend/src/lib/mail.utils.ts b/frontend/src/lib/mail.utils.ts new file mode 100644 index 0000000..e9338b1 --- /dev/null +++ b/frontend/src/lib/mail.utils.ts @@ -0,0 +1,30 @@ +import nodemailer from "nodemailer"; +import Mail from "nodemailer/lib/mailer"; +import SMTPTransport from "nodemailer/lib/smtp-transport"; + +const transport = nodemailer.createTransport({ + host: process.env.MAIL_HOST, + port: process.env.MAIL_PORT, + secure: process.env.NODE_ENV !== 'development', //true + auth: { + user: process.env.MAIL_USER, + pass: process.env.MAIL_PASSWORD + }, +} as SMTPTransport.Options) + +type SendEmailDto = { + sender: Mail.Address, + recipients: Mail.Address[], + subject: string; + message: string; +} +export const sendEmail = async (dto: SendEmailDto) => { + const { sender, recipients, subject, message} = dto; + + return await transport.sendMail({ + from: sender, + to: recipients, + html: message, + text: message, + }) +} \ No newline at end of file