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

feat: accept js #105

Draft
wants to merge 37 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
0ee2780
Fix logger name in AcceptHostedGateway
peelar Apr 18, 2024
e8e0e6a
add comment about buildTransactionFromTransactionInitializePayload
peelar Apr 18, 2024
cd05339
add basic boilerplate for accept.js
peelar Apr 18, 2024
9996d0c
add comment
peelar Apr 18, 2024
09aaeb8
update saleor schema version
peelar Apr 18, 2024
ead6c51
add basic setup for ListStoredPaymentMethods
peelar Apr 18, 2024
537588e
fix wrong webhook name
peelar Apr 19, 2024
0318d3a
add support for multiple payment gateways
peelar Apr 25, 2024
63efeeb
update acceptjs form integration
pankajmindpath Apr 23, 2024
93759c4
feat: making initialise array
JannikZed Apr 25, 2024
12ccd28
feat: making channel and other things dynamic
JannikZed Apr 25, 2024
2740de6
add support for multiple payment gateways
peelar Apr 25, 2024
26bb89c
Add support for customer profile
pankajmindpath Apr 26, 2024
97528da
remove state support
pankajmindpath Apr 26, 2024
c616124
add support for multiple payment gateways
peelar Apr 25, 2024
59febaa
update acceptjs form integration
pankajmindpath Apr 23, 2024
9a36672
update logic for initializePaymentGateway
pankajmindpath Apr 26, 2024
6dc8fec
update acceptjs form integration
pankajmindpath Apr 23, 2024
61440d4
feat: making channel and other things dynamic
JannikZed Apr 25, 2024
84940e2
add support for multiple payment gateways
peelar Apr 25, 2024
1168b42
Add logic for get stored payment method
pankajmindpath Apr 30, 2024
bc90ff9
Add support for adding customer profile and charge with payment profile
pankajmindpath Apr 30, 2024
0bab27c
create guest customer profile and profile type implementation: AcceptJS
pankajmindpath May 1, 2024
4e93e28
code refactoring: AcceptJS
pankajmindpath May 1, 2024
8d40130
Update customer profileType guest to regular : AcceptJS
pankajmindpath May 3, 2024
f23ff2d
update acceptjs form integration
pankajmindpath Apr 23, 2024
a037764
feat: making channel and other things dynamic
JannikZed Apr 25, 2024
9eff38b
create guest customer profile and profile type implementation: AcceptJS
pankajmindpath May 1, 2024
50b0de3
add support for multiple payment gateways
peelar Apr 25, 2024
ad3e0c3
update acceptjs form integration
pankajmindpath Apr 23, 2024
ec215c9
feat: making channel and other things dynamic
JannikZed Apr 25, 2024
4a9b89a
add support for multiple payment gateways
peelar Apr 25, 2024
a2461ad
update acceptjs form integration
pankajmindpath Apr 23, 2024
404cd8d
update payment id flow for transction: accept js
pankajmindpath May 14, 2024
80711a1
Bump next from 13.4.19 to 14.2.3 (#106)
dependabot[bot] May 13, 2024
1fe2f34
fix wrong webhook name
peelar Apr 19, 2024
95abbbb
Bump next from 13.4.19 to 14.2.3 (#106)
dependabot[bot] May 13, 2024
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
1 change: 1 addition & 0 deletions .graphqlrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ extensions:
scalars:
_Any: "unknown"
Date: "string"
Day: "number"
DateTime: "string"
Decimal: "number"
Minute: "number"
Expand Down
10 changes: 9 additions & 1 deletion example/.env.example
Original file line number Diff line number Diff line change
@@ -1 +1,9 @@
SALEOR_API_URL=
SALEOR_API_URL=""
NEXT_PUBLIC_SALEOR_API_URL=""

AUTHORIZE_ENVIRONMENT=""
AUTHORIZE_SALEOR_CHANNEL_SLUG=""
NEXT_PUBLIC_AUTHORIZE_API_LOGIN_ID=""
NEXT_PUBLIC_AUTHORIZE_TRANSACTION_KEY=""
NEXT_PUBLIC_AUTHORIZE_PUBLIC_CLIENT_KEY=""
NEXT_PUBLIC_SALEOR_CHANNEL=""
14 changes: 7 additions & 7 deletions example/graphql/CreateCheckout.graphql
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
mutation CreateCheckout($variantId: ID!) {
checkoutCreate(
input: {
channel: "default-channel"
channel: "ken-r"
lines: [{ quantity: 1, variantId: $variantId }]
languageCode: EN_US
email: "[email protected]"
billingAddress: {
firstName: "John"
lastName: "Doe"
streetAddress1: "813 Howard Street"
city: "Oswego"
streetAddress1: "500 8th Avenue"
city: "New York"
countryArea: "NY"
postalCode: "13126"
postalCode: "10018"
country: US
}
shippingAddress: {
firstName: "John"
lastName: "Doe"
streetAddress1: "813 Howard Street"
city: "Oswego"
streetAddress1: "500 8th Avenue"
city: "New York"
countryArea: "NY"
postalCode: "13126"
postalCode: "10018"
country: US
}
}
Expand Down
4 changes: 2 additions & 2 deletions example/graphql/PaymentGatewayInitialize.graphql
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
mutation PaymentGatewayInitialize($checkoutId: ID!, $data: JSON, $appId: String!) {
paymentGatewayInitialize(paymentGateways: [{ id: $appId, data: $data }], id: $checkoutId) {
mutation PaymentGatewayInitialize($checkoutId: ID!, $paymentGateways: [PaymentGatewayToInitialize!]) {
paymentGatewayInitialize(paymentGateways: $paymentGateways, id: $checkoutId) {
gatewayConfigs {
id
data
Expand Down
6 changes: 3 additions & 3 deletions example/graphql/ProductList.graphql
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
query ProductList {
query ProductList($channel: String) {
products(
first: 1
channel: "default-channel"
where: { isAvailable: true, giftCard: false }
channel: $channel
where: { isAvailable: true, giftCard: false, stockAvailability: IN_STOCK }
sortBy: { field: PRICE, direction: DESC }
) {
edges {
Expand Down
8 changes: 8 additions & 0 deletions example/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ const nextConfig = {
reactStrictMode: false,
images: {
domains: url ? [url.hostname] : [],
remotePatterns: [
{
protocol: "https",
hostname: url.hostname ?? "",
port: "",
pathname: "/w20/**",
},
],
},
};

Expand Down
8 changes: 4 additions & 4 deletions example/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

172 changes: 172 additions & 0 deletions example/src/accept-payment-form.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
import { gql, useMutation } from "@apollo/client";
import React, { FormEvent } from "react";
import { z } from "zod";
import {
TransactionInitializeDocument,
TransactionInitializeMutation,
TransactionInitializeMutationVariables,
TransactionProcessDocument,
TransactionProcessMutation,
TransactionProcessMutationVariables,
} from "../generated/graphql";
import { authorizeNetAppId } from "./lib/common";
import { getCheckoutId } from "./pages/cart";
import { useRouter } from "next/router";

import { useAcceptJs } from "react-acceptjs";

const authData = {
apiLoginID: process.env.NEXT_PUBLIC_AUTHORIZE_API_LOGIN_ID as string,
clientKey: process.env.NEXT_PUBLIC_AUTHORIZE_PUBLIC_CLIENT_KEY as string,
};

export interface IAuthorizeTransactionResponse {
amount: number;
result: string;
data: {
response: {
messages: {
resultCode: string;
};
transactionResponse: {
transId: string;
};
};
};
}

const acceptHostedTransactionResponseSchema = z.object({
messages: z.object({
resultCode: z.string().optional().default(""),
}),
transactionResponse: z.object({
transId: z.string().optional().default(""),
}),
});

export function AcceptPaymentForm() {
const checkoutId = getCheckoutId();
const router = useRouter();
const { dispatchData, loading, error } = useAcceptJs({ authData });
const [initializeTransaction] = useMutation<
TransactionInitializeMutation,
TransactionInitializeMutationVariables
>(gql(TransactionInitializeDocument.toString()));

const [processTransaction] = useMutation<TransactionProcessMutation, TransactionProcessMutationVariables>(
gql(TransactionProcessDocument.toString()),
);

const handleSubmit = React.useCallback(async (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();
// TODO use unknown because not getting currentTarget in event
const formData = new FormData((event as unknown as { target: HTMLFormElement }).target);
const cardData = {
cardNumber: (formData.get("cardNumber") as string) || "",
month: (formData.get("month") as string) || "",
year: (formData.get("year") as string) || "",
cardCode: (formData.get("cardCode") as string) || "",
};

// Dispatch CC data to Authorize.net and receive payment nonce for use on your server
const response = await dispatchData({ cardData });
getAcceptData(response.opaqueData);
}, []);

const getAcceptData = React.useCallback(
async (opaqueData: { dataDescriptor: string; dataValue: string }) => {
const initializeTransactionResponse = await initializeTransaction({
variables: {
checkoutId,
paymentGateway: authorizeNetAppId,
data: {
type: "acceptJs",
data: {
opaqueData,
},
},
},
});

// Need to handle error from authorize.net : start

if (
(initializeTransactionResponse.data?.transactionInitialize?.data as { error: string })?.error
?.length ||
initializeTransactionResponse.data?.transactionInitialize?.errors?.length
) {
throw new Error("Failed to initialize transaction");
}

const nextTransactionId = initializeTransactionResponse.data?.transactionInitialize?.transaction?.id;

if (!nextTransactionId) {
throw new Error("Transaction id not found in response");
}

transactionResponseHandler(
initializeTransactionResponse.data?.transactionInitialize?.data as {
response: IAuthorizeTransactionResponse;
},
nextTransactionId,
);

// Need to handle error from authorize.net : end
},
[initializeTransaction, checkoutId],
);

const transactionResponseHandler = React.useCallback(
async (rawResponse: { response: IAuthorizeTransactionResponse }, transactionId: string) => {
const authorizeResponse = acceptHostedTransactionResponseSchema.parse(rawResponse?.response);

const data = {
authorizeTransactionId: authorizeResponse?.transactionResponse?.transId,
};

if (!transactionId) {
throw new Error("Transaction id not found");
}

const processTransactionResponse = await processTransaction({
variables: {
transactionId,
data,
},
});

const isProcessTransactionSuccessful =
processTransactionResponse?.data?.transactionProcess?.transactionEvent?.type ===
"AUTHORIZATION_SUCCESS";

if (!isProcessTransactionSuccessful) {
throw new Error("Failed to process transaction");
}

router.push("/success");
},
[processTransaction, router],
);

return (
<>
<form onSubmit={handleSubmit} className="flex flex-col mt-4">
<label className="font-medium text-sm">Card Number</label>
<input className=" mb-2 border-2 p-2" type="text" name="cardNumber" placeholder="cardNumber" />
<label className="font-medium text-sm">Month</label>
<input className=" mb-2 border-2 p-2" type="text" name="month" placeholder="month" />
<label className="font-medium text-sm">Year</label>
<input className=" mb-2 border-2 p-2" type="text" name="year" placeholder="year" />
<label className="font-medium text-sm">Card Code</label>
<input className=" mb-2 border-2 p-2" type="text" name="cardCode" placeholder="cardCode" />
<button
type="submit"
disabled={loading || error}
className=" bg-slate-800 text-white p-2 rounded-lg"
>
Pay
</button>
</form>
</>
);
}
10 changes: 7 additions & 3 deletions example/src/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ import {
export default function Page() {
const { data, loading } = useQuery<ProductListQuery, ProductListQueryVariables>(
gql(ProductListDocument.toString()),
{
/**
* We pull an example product from this saleor channel.
*/
variables: { channel: process.env.NEXT_PUBLIC_SALEOR_CHANNEL },
},
);

const [createCheckout] = useMutation<CreateCheckoutMutation, CreateCheckoutMutationVariables>(
Expand All @@ -26,8 +32,7 @@ export default function Page() {
const [updateDelivery] = useMutation<UpdateDeliveryMutation, UpdateDeliveryMutationVariables>(
gql(UpdateDeliveryDocument.toString()),
);

const product = data?.products?.edges[0].node;
const product = data?.products?.edges[0]?.node;
const variant = product?.defaultVariant;

const router = useRouter();
Expand All @@ -40,7 +45,6 @@ export default function Page() {
e.preventDefault();

const response = await createCheckout({ variables: { variantId: variant.id } });

if (!response.data?.checkoutCreate?.checkout?.id) {
throw new Error("Failed to create checkout");
}
Expand Down
Loading
Loading