Skip to content
Open
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
37 changes: 37 additions & 0 deletions app/(api)/_graphql/mutations/saveInfo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
A mutation that I hope works that's meant to save the billing info
so that we don't have to go on Stripe to see it
*/

import { gql } from '@apollo/client';

export const SAVE_BILLING_INFO = gql`
mutation SaveBillingInfo(
$secret: String!
$id: String!
$name: String!
$address: String!
$address2: String
$city: String!
$state: String!
$zip: String!
$phone: String!
$paymentMethod: String!
) {
saveBillingInfo(
secret: $secret
id: $id
name: $name
address: $address
address2: $address2
city: $city
state: $state
zip: $zip
phone: $phone
paymentMethod: $paymentMethod
) {
success
message
}
}
`;
41 changes: 41 additions & 0 deletions app/(api)/_graphql/queries/getOrders.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Queries for grabbing orders that I hope works T_T

import { gql } from '@apollo/client';

export const GET_ALL_ORDERS = gql`
query GetAllOrders {
orders {
id
secret
name
address
address2
city
state
zip
phone
paymentMethod
createdAt
updatedAt
}
}
`;

export const GET_ORDER_BY_ID = gql`
query GetOrderById($id: [ID]) {
order(id: $id) {
id
secret
name
address
address2
city
state
zip
phone
paymentMethod
createdAt
updatedAt
}
}
`;
29 changes: 29 additions & 0 deletions app/(api)/api/checkout_sessions/get.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { NextRequest, NextResponse } from 'next/server';
import stripe from 'stripe';

export async function GET(request: NextRequest) {
try {
const auth_stripe = new stripe(process.env.STRIPE_SECRET_KEY!);
const searchParams = request.nextUrl.searchParams;
const session_id = searchParams.get('session_id');

const session = await auth_stripe.checkout.sessions.retrieve(
session_id as string
);

return NextResponse.json(
{
customer_email: session.customer_details!.email,
},
{
status: 200,
}
);
} catch (e) {
const error = e as stripe.StripeRawError;
return NextResponse.json(
{ ok: false, body: null, error: error.message },
{ status: 400 }
);
}
}
31 changes: 31 additions & 0 deletions app/(api)/api/checkout_sessions/post.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { NextRequest, NextResponse } from 'next/server';
import stripe from 'stripe';

export async function POST(request: NextRequest) {
try {
const { total } = await request.json();
const auth_stripe = new stripe(process.env.STRIPE_SECRET_KEY!);

// Creates a checkout session from body params.
const session = await auth_stripe.paymentIntents.create({
amount: total * 100,
currency: 'usd',
payment_method_types: ['card'],
});

return NextResponse.json(
{
clientSecret: session.client_secret,
},
{
status: 200,
}
);
} catch (e) {
const error = e as stripe.StripeRawError;
return NextResponse.json(
{ ok: false, body: null, error: error.message },
{ status: 400 }
);
}
}
2 changes: 2 additions & 0 deletions app/(api)/api/checkout_sessions/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { POST } from './post';
export { GET } from './get';
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// This file could honestly be removed but for now I'll keep it here
// in case it still has some use I might not be seeing

'use client';

import styles from './CheckoutCart.module.scss';
Expand All @@ -8,10 +11,11 @@ export default function CheckoutCart() {
if (loading) {
return 'loading...';
}

return (
<div className={styles.container}>
{JSON.stringify(cart)}
<p>total cost: ${compute_total()}</p>
{/* {JSON.stringify(cart)} */}
{/* <p>total cost: ${compute_total()}</p> */}
</div>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import styles from './DeliveryFormSection.module.scss';

export default function DeliveryFormSection() {
return (
<form className={styles.delivery_form}>
<div className={styles.delivery_form}>
<h2 className={styles.heading}>Delivery</h2>
<DeliveryOptions />
<ShippingInfo />
</form>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import InputField from '../InputField/InputField';
import Address from '../Address/Address';
import PaymentForm from '../../../PaymentForm/PaymentForm';

import { useState } from 'react';
import { GoQuestion } from 'react-icons/go';
Expand Down Expand Up @@ -78,6 +79,15 @@ export default function ShippingInfo() {
icon={GoQuestion}
handleFieldChange={updateShippingField}
/>
<PaymentForm
name={`${shippingInfo.firstName!} ${shippingInfo.lastName}`}
address={shippingInfo.address!}
address2={shippingInfo.apartment!}
city={shippingInfo.city!}
state={shippingInfo.state!}
zip={shippingInfo.zip!}
phone={shippingInfo.phone!}
/>
</div>
);
}
31 changes: 31 additions & 0 deletions app/(pages)/checkout/_components/PaymentForm/CardSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React from 'react';
import { CardElement } from '@stripe/react-stripe-js';
// import './Styles.css';
const CARD_ELEMENT_OPTIONS = {
style: {
base: {
color: '#32325d',
fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
fontSmoothing: 'antialiased',
fontSize: '16px',
'::placeholder': {
color: '#aab7c4',
},
},
invalid: {
color: '#fa755a',
iconColor: '#fa755a',
},
},
};
function CardSection() {
return (
<div>
<label>
Card details
<CardElement options={CARD_ELEMENT_OPTIONS} />
</label>
</div>
);
}
export default CardSection;
111 changes: 111 additions & 0 deletions app/(pages)/checkout/_components/PaymentForm/CheckoutForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import React from 'react';
import { useStripe, useElements, CardElement } from '@stripe/react-stripe-js';
import CardSection from './CardSection';
import Stripe from 'stripe';
import { useMutation } from '@apollo/client';
import { SAVE_BILLING_INFO } from '@graphql/mutations/saveInfo';

export default function CheckoutForm({
secret,
name,
address,
address2,
city,
state,
zip,
phone,
}: {
secret: string;
name: string;
address: string;
address2: string;
city: string;
state: string;
zip: string;
phone: string;
}) {
const stripe = useStripe();
const elements = useElements();
const key = process.env.NEXT_PUBLIC_STRIPE_SECRET_KEY;
const payment = new Stripe(`${key}`);
const [saveBillingInfo] = useMutation(SAVE_BILLING_INFO);

const handleSubmit = async (event: { preventDefault: () => void }) => {
// We don't want to let default form submission happen here,
// which would refresh the page.
event.preventDefault();

if (!stripe || !elements) {
// Stripe.js hasn't yet loaded.
// Make sure to disable form submission until Stripe.js has loaded.
return;
}

const result = await stripe.confirmCardPayment(`${secret}`, {
payment_method: {
card: elements.getElement(CardElement)!,
billing_details: {
name: name,
address: {
city: city,
country: 'US',
line1: address,
line2: address2,
postal_code: zip,
state: state,
},
phone: phone,
},
},
});

if (result.error) {
// Show error to your customer (for example, insufficient funds)
console.log(result.error.message);
} else {
// The payment has been processed!
if (result.paymentIntent.status === 'succeeded') {
// Show a success message to your customer
// There's a risk of the customer closing the window before callback
// execution. Set up a webhook or plugin to listen for the
// payment_intent.succeeded event that handles any business critical
// post-payment actions.
const intent = result.paymentIntent.payment_method;

const paymentMethod = await payment.paymentMethods.retrieve(
`${intent}`,
{
apiKey: `${key}`,
}
);
console.log('method: ', paymentMethod);

try {
const { data } = await saveBillingInfo({
variables: {
secret,
paymentMethod: paymentMethod.id,
name: paymentMethod.billing_details.name,
address: paymentMethod.billing_details.address?.line1,
address2: paymentMethod.billing_details.address?.line2,
city: paymentMethod.billing_details.address?.city,
state: paymentMethod.billing_details.address?.state,
zip: paymentMethod.billing_details.address?.postal_code,
phone: paymentMethod.billing_details.phone,
},
});
console.log(data);
} catch (error) {
console.error('Someone sux at graphql routes (error msg): ', error);
}
}
}
};

return (
<form onSubmit={handleSubmit}>
<CardSection />
<button disabled={!stripe}>Confirm order</button>
</form>
);
}
Loading