Skip to content
Merged
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
18 changes: 18 additions & 0 deletions .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: Code quality

on:
push:
pull_request:

jobs:
quality:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Biome
uses: biomejs/setup-biome@v2
with:
version: latest
- name: Run Biome
run: biome ci .
18 changes: 15 additions & 3 deletions biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@
"clientKind": "git",
"useIgnoreFile": false
},
"files": {
"ignoreUnknown": false
},
"formatter": {
"enabled": true,
"indentStyle": "tab"
Expand All @@ -30,5 +27,20 @@
"organizeImports": "on"
}
}
},
"files": {
"includes": [
"**",
"!**/node_modules/**",
"!**/dist/**",
"!**/build/**",
"!**/coverage/**",
"!**/.git/**",
"!**/.vscode/**",
"!**/.idea/**",
"!**/.DS_Store",
"!**/Thumbs.db"
],
"ignoreUnknown": true
}
}
2 changes: 1 addition & 1 deletion components/Icons/FacebookIcon.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Icon } from "@chakra-ui/react";
export default function FacebookIcon(props: any) {
export default function FacebookIcon(props: React.ComponentProps<typeof Icon>) {
return (
<Icon {...props}>
<path
Expand Down
4 changes: 3 additions & 1 deletion components/Icons/InstagramIcon.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Icon } from "@chakra-ui/react";

export default function InstagramIcon(props: any) {
export default function InstagramIcon(
props: React.ComponentProps<typeof Icon>,
) {
return (
<Icon viewBox="0 0 250 250" {...props}>
<g>
Expand Down
6 changes: 3 additions & 3 deletions components/itemmodal/ItemModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ import {

type Props = {
isOpen: boolean;
closeFunction: () => any;
creditCard: () => any;
bankTransfer: () => any;
closeFunction: () => void;
creditCard: () => void;
bankTransfer: () => void;
};

export default function ItemModal({
Expand Down
13 changes: 4 additions & 9 deletions components/ordercontainer/Cart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import QuantityPicker from "../quantitypicker/QuantityPicker";

type Props = {
smallScreen: boolean;
formRef: any;
formRef: React.RefObject<HTMLFormElement>;
};

const CartItemContainer = () => {
Expand Down Expand Up @@ -137,16 +137,11 @@ const PdfItemContainer = () => {
};

const Cart = ({ smallScreen, formRef }: Props) => {
const {
cartPackages,
uploadedPdfs,
displayPriceString,
setIsModalOpen,
hasDiscountApplied,
} = useContext(CartContext);
const { cartPackages, uploadedPdfs, displayPriceString, setIsModalOpen } =
useContext(CartContext);
const checkFormValidity = () => {
const form = formRef.current;
const formValid = form.checkValidity();
const formValid = form?.checkValidity();
if (!formValid) window.alert("Please check your submission details.");
return formValid;
};
Expand Down
2 changes: 1 addition & 1 deletion components/ordercontainer/DetailsForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const DetailsForm = ({ formRef }: Props) => {
<Input name="email" type="email" borderRadius="sm" />
</Box>
<FormLabel>Extra requests</FormLabel>
<Textarea name="message" type="text" borderRadius="sm" />
<Textarea name="message" borderRadius="sm" />
</form>
</Box>
);
Expand Down
6 changes: 3 additions & 3 deletions components/ordercontainer/OrderContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import PackageOrder from "./PackageOrder";
import PdfOrder from "./PdfOrder";

type Props = {
packages: any;
packages: StripeBackendItem[];
};

const OrderContainer = ({ packages }: Props) => {
Expand All @@ -44,7 +44,7 @@ const OrderContainerInner = ({ packages }: Props) => {
>([]);
const [isProcessing, setIsProcessing] = useState(false);
const [smallScreen] = useMediaQuery(`(max-width: 1000px)`);
const formRef = useRef(null);
const formRef = useRef<HTMLFormElement>(null);
const router = useRouter();

const closeModal = () => {
Expand Down Expand Up @@ -183,7 +183,7 @@ const OrderContainerInner = ({ packages }: Props) => {
return uploadPdf(file, fileName, index);
});

const tempItems: any[] = [];
const tempItems: { name: string; url: string }[] = [];
Promise.all(promises)
.then((res) => {
res.map((item) =>
Expand Down
2 changes: 0 additions & 2 deletions components/productcard/ProductCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,12 @@ import styles from "./ProductCard.module.css";

type Props = {
orderPackage: StripeProduct;
image: string;
hasButton: boolean;
addFunction: IAddOrder;
};

export default function ProductCard({
orderPackage,
image,
hasButton,
addFunction,
}: Props) {
Expand Down
4 changes: 3 additions & 1 deletion contexts/CartContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ const alreadyInArray = <T extends CartItem>(
return arrayToSearch.some((item) => item.id === itemToCheck.id);
};

export function CartContextProvider(props: any) {
export function CartContextProvider(
props: React.PropsWithChildren<Record<string, never>>,
) {
const [cartPackages, setCartPackages] = useState<CartItem[]>([]);
const [uploadedPdfs, setUploadedPdfs] = useState<PdfCartItem[]>([]);
const [displayPriceString, setDisplayPriceString] = useState<string>(
Expand Down
9 changes: 9 additions & 0 deletions lefthook.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
pre-commit:
jobs:
- name: check staged files
run: pnpm biome check {staged_files} --write --no-errors-on-unmatched

pre-push:
jobs:
- name: run ci tests
run: pnpm biome ci .
6 changes: 3 additions & 3 deletions lib/mongo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ if (!MONGODB_URI) {
throw new Error("Define the MONGODB_URI environmental variable");
}

let cachedClient: any = null;
let cachedDb: any = null;
let cachedClient: MongoClient | null = null;
let cachedDb: ReturnType<MongoClient["db"]> | null = null;

export async function connectToDatabase(dbName: string) {
// check the cached.
Expand All @@ -22,7 +22,7 @@ export async function connectToDatabase(dbName: string) {
}

// Connect to cluster
const client = new MongoClient(MONGODB_URI!);
const client = new MongoClient(MONGODB_URI || "");
await client.connect();
const db = client.db(dbName);

Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,16 @@
"react": "18.2.0",
"react-dom": "18.2.0",
"react-messenger-chat-plugin": "^3.0.5",
"stripe": "^12.1.1"
"stripe": "^12.1.1",
"zod": "^4.0.5"
},
"devDependencies": {
"@biomejs/biome": "2.1.1",
"@types/node": "18.6.2",
"@types/react": "18.0.15",
"@types/react-dom": "18.0.6",
"eslint-config-next": "12.2.3",
"lefthook": "^1.12.2",
"typescript": "4.7.4"
},
"engines": {
Expand Down
45 changes: 38 additions & 7 deletions pages/api/checkout.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,66 @@
import type { NextApiRequest, NextApiResponse } from "next";
import { z } from "zod";
import {
createCoupons,
createSession,
createUniqueProductsForDuplicates,
} from "../../lib/stripe";

const CheckoutSchema = z.object({
items: z.array(
z.object({
id: z.string(),
quantity: z.number().min(1),
name: z.string(),
price: z.string(), // Changed to string to match expected type
productId: z.string(),
priceId: z.string(),
}),
),
orderId: z.string(),
email: z.string().email(),
});

export default async function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
try {
const items = JSON.parse(req.body);
const parsedBody = CheckoutSchema.parse(JSON.parse(req.body));

const updatedItems = await createUniqueProductsForDuplicates(items.items);
const updatedItems = await createUniqueProductsForDuplicates(
parsedBody.items,
);
const coupon = await createCoupons(updatedItems);

const session = await createSession(
updatedItems,
items.orderId,
items.email,
parsedBody.orderId,
parsedBody.email,
coupon,
);

if (!session.metadata || !session.metadata.orderId) {
return res.status(500).json({
message: "Session metadata is missing orderId",
success: false,
});
}

return res.json({
paymentLink: session.url,
orderId: session.metadata.orderId,
success: true,
});
} catch (error) {
// return the error
return res.json({
message: new Error(error).message,
if (error instanceof z.ZodError) {
return res.status(400).json({
message: error.issues,
success: false,
});
}
return res.status(500).json({
message: error instanceof Error ? error.message : "Unknown error",
success: false,
});
}
Expand Down
30 changes: 25 additions & 5 deletions pages/api/checkpaymentstatus.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,31 @@
import type { NextApiRequest, NextApiResponse } from "next";
import { z } from "zod";
import { updatePaymentStatus } from "../../lib/google";
import { checkSession } from "../../lib/stripe";

const CheckPaymentStatusSchema = z.object({
session_id: z.string(),
});

export default async function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
try {
const success = await checkSession(req.query.session_id);
const parsedQuery = CheckPaymentStatusSchema.parse(req.query);

const success = await checkSession(parsedQuery.session_id);
const orderId = success.orderId;
const customer = success.customer;
const price = success.price;

if (!process.env.BASE_URL) {
return res.status(500).json({
message: "BASE_URL environment variable is not defined.",
success: false,
});
}

if (success.paid) {
updatePaymentStatus(orderId);
await fetch(`${process.env.BASE_URL}/api/sendemailcreditcard`, {
Expand All @@ -19,17 +34,22 @@ export default async function handler(
name: customer?.name,
email: customer?.email,
orderId: orderId,
price: price / 100,
price: price || NaN / 100,
}),
});
return res.redirect(307, `/success?orderId=${orderId}`);
} else {
return res.redirect(307, "/order");
}
} catch (error) {
// return the error
return res.json({
message: new Error(error).message,
if (error instanceof z.ZodError) {
return res.status(400).json({
message: error.issues,
success: false,
});
}
return res.status(500).json({
message: error instanceof Error ? error.message : "Unknown error",
success: false,
});
}
Expand Down
Loading