Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shop page #27

Draft
wants to merge 18 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions app/(site)/shop/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { getProducts } from "components/Shop/SizePicker/payloadAction"
import React from "react";
import ShopPageContent from "./pageContent";

export default async function ShopPage() {

const products = (await getProducts()).docs

return <ShopPageContent products={products} />;
}
60 changes: 60 additions & 0 deletions app/(site)/shop/pageContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
"use client";

import SectionHeader from "@/components/Common/SectionHeader";
import ShopCart from "@/components/Shop/Cart";
import CartItem from "@/components/Shop/CartItem";
import ProductPreview from "@/components/Shop/ProductPreview";
import ShopCard from "@/components/Shop/ShopCard";
import { Product } from "@/payload-types";
import { cartProduct } from "@/types/cartProduct";
import React from "react";

export default function ShopPageContent({ products }) {
const [previewProduct, setPreviewProduct] = React.useState(products[0]);
const [openCart, setOpenCart] = React.useState(false);
const [cartProducts, setCardProducts] = React.useState<cartProduct[]>([]);

const addToCart = (item: cartProduct) => {
setCardProducts((prevCardProducts) => {
if (prevCardProducts.some((p) => p.product.id === item.product.id && p.size === item.size)) {
return prevCardProducts;
}
return [...prevCardProducts, item];
});
}

const removeFromCart = (itemCart: cartProduct) => {
setCardProducts((prevCardProducts) => prevCardProducts.filter((item) => item.product.id !== itemCart.product.id || (item.product.id === itemCart.product.id && item.size !== itemCart.size)));
}

return (
<>
<div className="flex flex-row my-5 mx-20 mt-40">
<section className="flex flex-col max-w-[300px]">
<ProductPreview product={previewProduct} setCartState={setOpenCart} addToCart={addToCart}></ProductPreview>
</section>
<ShopCart isOpen={openCart} onOpenChange={setOpenCart} products={cartProducts} removeFromCart={removeFromCart}></ShopCart>
<section className="flex flex-col ml-30">
<h1 className="text-7xl font-serif tracking-tight text-black">
Student Essentials
</h1>
<h1 className="text-2xl font-serif text-black mt-5 tracking-tight max-w-96">
Os <span className="text-engenharia italic">merch-essentials</span>{" "}
deste ano para viveres a tua vida académica ao máximo, com estilo.
</h1>
<div>
<div className="mt-10 flex gap-2">
{products.map((product: Product) => (
<ShopCard
product={product}
key={product.id}
customClick={() => setPreviewProduct(product)}
></ShopCard>
))}
</div>
</div>
</section>
</div>
</>
);
}
3 changes: 3 additions & 0 deletions app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
body {
@apply relative z-1 font-inter text-regular font-normal text-waterloo dark:text-manatee;
}
:root {
--radius: 0.5rem;
}
}

@layer components {
Expand Down
37 changes: 37 additions & 0 deletions collections/Order.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { CollectionConfig } from "payload";

export const Order: CollectionConfig = {
slug: 'order',
labels: {
singular: 'Order',
plural: 'Orders'
},
fields: [
{
name: "email",
label: "Email",
type: "text",
required: true,
},
{
name: "products",
label: "Produtos",
type: "array",
fields: [
{
name: "product",
label: "Product",
type: "relationship",
relationTo: "product",
required: true,
},
],
required: true
},
{
name: "price",
type: "number",
required: true,
},
]
}
66 changes: 66 additions & 0 deletions collections/Product.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import type { CollectionConfig } from "payload";

export const Product: CollectionConfig = {
slug: "product",
fields: [
{
name: "name",
type: "text",
required: true,
},
{
name: "price",
type: "number",
required: true,
},
{
name: "description",
type: "text",
required: true,
},
{
name: "color",
type: "text",
required: true,
},
{
name: "instances",
type: "array",
fields: [
{
name: "Size",
type: "select",
hasMany: false,
options: [
{
label: "XS",
value: "XS"
},
{
label: "S",
value: "S"
},
{
label: "M",
value: "M"
},
{
label: "L",
value: "L"
},
{
label: "XL",
value: "XL"
},
],
required: true,
},
{
name: "quantity",
type: "number",
required: true,
}
]
}
],
};
20 changes: 20 additions & 0 deletions components.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "default",
"rsc": true,
"tsx": true,
"tailwind": {
"config": "tailwind.config.js",
"css": "app/globals.css",
"baseColor": "slate",
"cssVariables": false,
"prefix": ""
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
}
}
62 changes: 62 additions & 0 deletions components/Shop/Cart/apiCall.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import axios from 'axios';
import { paymentStatus } from '.';

export async function requestMBWAY(phoneNumber: string, amount: number, setPaymentStatus: (status: paymentStatus) => void) {
console.log("Function requestMBWAY called with:", phoneNumber, amount);

const options = {
method: 'POST',
url: 'https://api.ifthenpay.com/spg/payment/mbway',
headers: { 'Content-Type': 'application/json' },
data: {
mbWayKey: 'BYX-186558',
orderId: 'teste',
amount: amount.toString(),
mobileNumber: '351#' + phoneNumber,
}
};

console.log("Options prepared:", options);

try {
const { data } = await axios.request(options);
console.log("Response data:", data);
pollPaymentStatus(data.RequestId, setPaymentStatus);
return;
} catch (error) {
console.error("Error occurred:", error);
}
}

export async function checkPayment(requestID: string) {
const options = {
method: 'GET',
url: 'https://api.ifthenpay.com/spg/payment/mbway/status',
params: { mbWayKey: 'BYX-186558', requestId: requestID }
};

try {
const { data } = await axios.request(options);
console.log(data);
return data;
} catch (error) {
console.error(error);
}
}

const pollPaymentStatus = (requestID: string, setPaymentStatus: (status: paymentStatus) => void) => {
const pollStatus = setInterval(async () => {
const status = await checkPayment(requestID)

if (status.Message == "Success") {
alert("euerka");
setPaymentStatus(paymentStatus.confirmed)
clearInterval(pollStatus)
}
if (status.Message == "Declined by user") {
alert("declined by user");
setPaymentStatus(paymentStatus.declined)
clearInterval(pollStatus)
}
}, 5000)
}
73 changes: 73 additions & 0 deletions components/Shop/Cart/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import {
Sheet,
SheetContent,
SheetDescription,
SheetFooter,
SheetHeader,
SheetTitle,
} from "@/components/ui/sheet"
import React from "react";
import CartItem from "../CartItem";
import { cartProduct } from "@/types/cartProduct";
import PaymentForm from "../PaymentForm";
import PuffLoader from "react-spinners/PuffLoader";
import { Check, CircleAlert } from "lucide-react";

type ShopCartProps = {
isOpen: boolean,
onOpenChange: (bool: boolean) => void,
products: cartProduct[],
removeFromCart: (item: cartProduct) => void,
}

export enum paymentStatus {
confirmed,
declined,
waiting
}

const ShopCart = ({ isOpen, onOpenChange, products, removeFromCart }: ShopCartProps) => {
const [number, setNumber] = React.useState("")
const [processingPayment, setProcessingPayment] = React.useState(false)
const [paymentStatusState, setPaymentStatus] = React.useState<paymentStatus>(paymentStatus.waiting)

return <Sheet open={isOpen} onOpenChange={onOpenChange}>
<SheetContent className="z-100000 flex flex-col justify-between">
<SheetHeader>
<SheetTitle className="mb-5">Cart</SheetTitle>
<SheetDescription className="flex flex-col gap-5">
{products.map((p) => {
return <>
<CartItem item={p} removeFromCart={removeFromCart}></CartItem>
</>
})}
</SheetDescription>
</SheetHeader>
<SheetFooter className="!flex !flex-col">
<SheetTitle className="mb-5">Payment</SheetTitle>
{!processingPayment ? <PaymentForm setNumber={setNumber} products={products} setProcessingPayment={setProcessingPayment} setPaymentStatus={setPaymentStatus}></PaymentForm> :
<div className="flex gap-2 justify-center bg-gray-100 p-5 rounded">
{
paymentStatusState == paymentStatus.waiting ?
<>
<h2>Waiting for confirmation</h2>
<PuffLoader size={25} color="#90ee90" />
</> : paymentStatusState == paymentStatus.declined ?
<>
<h2>Payment declined</h2>
<CircleAlert color="red" />
</> :
<>
<h2>Payment processed</h2>
<Check color="#90ee90" />
</>
}

</div>
}
</SheetFooter >
</SheetContent >
</Sheet >
}

export default ShopCart;
12 changes: 12 additions & 0 deletions components/Shop/Cart/payment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { cartProduct } from "@/types/cartProduct";
import { requestMBWAY } from "./apiCall";
import { paymentStatus } from ".";

export default async function startPaymentProcess(products: cartProduct[], setPaymentStatus: (status: paymentStatus) => void) {
await requestMBWAY("915612870", calculcateCost(products), setPaymentStatus);
}

function calculcateCost(products: cartProduct[]) {
const totalCost = 0
return products.reduce((prev, curr) => prev + curr.product.price, totalCost)
}
Loading